Merge branch 'develop' into fix-ra-rdnss
This commit is contained in:
commit
7286491c16
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,6 +12,7 @@
|
||||
*~
|
||||
obj_*
|
||||
Makefile.target
|
||||
Makefile.*.defines
|
||||
tools/doxygen/html
|
||||
patches-*
|
||||
tools/tunslip
|
||||
|
@ -31,3 +31,4 @@ env:
|
||||
- TEST_NAME='compile-nxp-ports'
|
||||
- TEST_NAME='doxygen'
|
||||
- TEST_NAME='compile-tools'
|
||||
- TEST_NAME='native-runs'
|
||||
|
@ -17,7 +17,9 @@ CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES
|
||||
### Compilation rules
|
||||
CUSTOM_RULE_LINK = 1
|
||||
|
||||
%.elf: $(CPU_STARTFILES) %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a $(LDSCRIPT)
|
||||
.SECONDEXPANSION:
|
||||
|
||||
%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT)
|
||||
$(TRACE_LD)
|
||||
$(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -lm -o $@
|
||||
|
||||
|
@ -36,8 +36,6 @@ CPU_START_SOURCEFILES = startup-gcc.c
|
||||
CONTIKI_SOURCEFILES += $(CONTIKI_CPU_SOURCEFILES) $(DEBUG_IO_SOURCEFILES)
|
||||
CONTIKI_SOURCEFILES += $(USB_SOURCEFILES)
|
||||
|
||||
.SECONDEXPANSION:
|
||||
|
||||
### Always re-build ieee-addr.o in case the command line passes a new NODEID
|
||||
FORCE:
|
||||
|
||||
|
@ -209,7 +209,7 @@ static const output_config_t output_power[] = {
|
||||
#define OUTPUT_POWER_UNKNOWN 0xFFFF
|
||||
|
||||
/* Default TX Power - position in output_power[] */
|
||||
const output_config_t *tx_power_current = &output_power[0];
|
||||
static const output_config_t *tx_power_current = &output_power[0];
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static volatile int8_t last_rssi = 0;
|
||||
static volatile uint8_t last_corr_lqi = 0;
|
||||
|
@ -203,7 +203,7 @@ extern const prop_mode_tx_power_config_t TX_POWER_DRIVER[];
|
||||
#define OUTPUT_POWER_UNKNOWN 0xFFFF
|
||||
|
||||
/* Default TX Power - position in output_power[] */
|
||||
const prop_mode_tx_power_config_t *tx_power_current = &TX_POWER_DRIVER[1];
|
||||
static const prop_mode_tx_power_config_t *tx_power_current = &TX_POWER_DRIVER[1];
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifdef PROP_MODE_CONF_LO_DIVIDER
|
||||
#define PROP_MODE_LO_DIVIDER PROP_MODE_CONF_LO_DIVIDER
|
||||
|
@ -79,11 +79,11 @@ rtimer_arch_schedule(rtimer_clock_t t)
|
||||
|
||||
c = t - (unsigned short)clock_time();
|
||||
|
||||
val.it_value.tv_sec = c / 1000;
|
||||
val.it_value.tv_usec = (c % 1000) * 1000;
|
||||
val.it_value.tv_sec = c / CLOCK_SECOND;
|
||||
val.it_value.tv_usec = (c % CLOCK_SECOND) * CLOCK_SECOND;
|
||||
|
||||
PRINTF("rtimer_arch_schedule time %u %u in %d.%d seconds\n", t, c, c / 1000,
|
||||
(c % 1000) * 1000);
|
||||
PRINTF("rtimer_arch_schedule time %u %u in %d.%d seconds\n", t, c, val.it_value.tv_sec,
|
||||
val.it_value.tv_usec);
|
||||
|
||||
val.it_interval.tv_sec = val.it_interval.tv_usec = 0;
|
||||
setitimer(ITIMER_REAL, &val, NULL);
|
||||
|
@ -178,6 +178,8 @@ vpath %.s $(ASM_PATHS)
|
||||
|
||||
OBJECTS = $(C_OBJECTS) $(ASM_OBJECTS)
|
||||
|
||||
CLEAN += nrf52832.a
|
||||
|
||||
TARGET_LIBS= nrf52832.a $(NRF52_SDK_ROOT)/components/iot/ble_6lowpan/lib/ble_6lowpan.a
|
||||
|
||||
nrf52832.a: $(OBJECTS)
|
||||
|
@ -19,6 +19,10 @@ else
|
||||
CONTIKI_TARGET_SOURCEFILES += tun6-net.c
|
||||
endif
|
||||
|
||||
ifeq ($(HOST_OS),Linux)
|
||||
TARGET_LIBFILES += -lrt
|
||||
endif
|
||||
|
||||
CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES)
|
||||
|
||||
.SUFFIXES:
|
||||
|
@ -42,24 +42,49 @@
|
||||
#include <sys/time.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
clock_time_t
|
||||
clock_time(void)
|
||||
typedef struct clock_timespec_s {
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
} clock_timespec_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
get_time(clock_timespec_t *spec)
|
||||
{
|
||||
#if defined(__linux__) || (defined(__MACH__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
|
||||
struct timespec ts;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
spec->tv_sec = ts.tv_sec;
|
||||
spec->tv_nsec = ts.tv_nsec;
|
||||
#else
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
spec->tv_sec = tv.tv_sec;
|
||||
spec->tv_nsec = tv.tv_usec * 1000;
|
||||
#endif
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
clock_time_t
|
||||
clock_time(void)
|
||||
{
|
||||
clock_timespec_t ts;
|
||||
|
||||
get_time(&ts);
|
||||
|
||||
return ts.tv_sec * CLOCK_SECOND + ts.tv_nsec / (1000000000 / CLOCK_SECOND);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned long
|
||||
clock_seconds(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
clock_timespec_t ts;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
get_time(&ts);
|
||||
|
||||
return tv.tv_sec;
|
||||
return ts.tv_sec;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
|
@ -158,6 +158,7 @@ set_lladdr(void)
|
||||
linkaddr_set_node_addr(&addr);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if NETSTACK_CONF_WITH_IPV6
|
||||
static void
|
||||
set_global_address(void)
|
||||
{
|
||||
@ -183,6 +184,7 @@ set_global_address(void)
|
||||
uip_ip6addr(&ipaddr, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 1);
|
||||
uip_ds6_defrt_add(&ipaddr, 0);
|
||||
}
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int contiki_argc = 0;
|
||||
char **contiki_argv;
|
||||
|
@ -70,12 +70,12 @@
|
||||
/* Platform-specific define to signify sensor reading failure */
|
||||
#define CC26XX_SENSOR_READING_ERROR 0x80000000
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* board.h assumes that basic configuration is done */
|
||||
#include "board.h"
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Include CPU-related configuration */
|
||||
#include "cc13xx-cc26xx-conf.h"
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* board.h assumes that basic configuration is done */
|
||||
#include "board.h"
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* CONTIKI_CONF_H */
|
||||
|
||||
/** @} */
|
||||
|
7
examples/libs/data-structures/Makefile
Normal file
7
examples/libs/data-structures/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
CONTIKI_PROJECT = data-structures
|
||||
|
||||
all: $(CONTIKI_PROJECT)
|
||||
|
||||
CONTIKI = ../../..
|
||||
|
||||
include $(CONTIKI)/Makefile.include
|
383
examples/libs/data-structures/data-structures.c
Normal file
383
examples/libs/data-structures/data-structures.c
Normal file
@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
|
||||
* Copyright (c) 2017, James Pope
|
||||
* 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 "lib/stack.h"
|
||||
#include "lib/queue.h"
|
||||
#include "lib/circular-list.h"
|
||||
#include "lib/dbl-list.h"
|
||||
#include "lib/dbl-circ-list.h"
|
||||
#include "lib/random.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(data_structure_process, "Data structure process");
|
||||
AUTOSTART_PROCESSES(&data_structure_process);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
STACK(demo_stack);
|
||||
QUEUE(demo_queue);
|
||||
CIRCULAR_LIST(demo_cll);
|
||||
DBL_LIST(demo_dbl);
|
||||
DBL_CIRC_LIST(demo_dblcl);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
typedef struct demo_struct_s {
|
||||
struct demo_struct_s *next;
|
||||
struct demo_struct_s *previous;
|
||||
unsigned short value;
|
||||
} demo_struct_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define DATA_STRUCTURE_DEMO_ELEMENT_COUNT 4
|
||||
static demo_struct_t elements[DATA_STRUCTURE_DEMO_ELEMENT_COUNT];
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
dbl_circ_list_print(dbl_circ_list_t dblcl)
|
||||
{
|
||||
demo_struct_t *this = *dblcl;
|
||||
|
||||
if(*dblcl == NULL) {
|
||||
printf("Length=0\n");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
printf("<--(0x%04x)--0x%04x--(0x%04x)-->", this->previous->value,
|
||||
this->value, this->next->value);
|
||||
this = this->next;
|
||||
} while(this != *dblcl);
|
||||
|
||||
printf(" (Length=%lu)\n", dbl_circ_list_length(dblcl));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
demonstrate_dbl_circ_list(void)
|
||||
{
|
||||
int i;
|
||||
demo_struct_t *this;
|
||||
|
||||
dbl_circ_list_init(demo_dblcl);
|
||||
printf("============================\n");
|
||||
printf("Circular, doubly-linked list\n");
|
||||
|
||||
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
|
||||
elements[i].next = NULL;
|
||||
elements[i].previous = NULL;
|
||||
}
|
||||
|
||||
/* Add elements */
|
||||
dbl_circ_list_add_tail(demo_dblcl, &elements[0]);
|
||||
printf("Add tail : 0x%04x | ", elements[0].value);
|
||||
dbl_circ_list_print(demo_dblcl);
|
||||
|
||||
dbl_circ_list_add_after(demo_dblcl, &elements[0], &elements[1]);
|
||||
printf("Add after : 0x%04x | ", elements[1].value);
|
||||
dbl_circ_list_print(demo_dblcl);
|
||||
|
||||
dbl_circ_list_add_head(demo_dblcl, &elements[2]);
|
||||
printf("Add head : 0x%04x | ", elements[2].value);
|
||||
dbl_circ_list_print(demo_dblcl);
|
||||
|
||||
dbl_circ_list_add_before(demo_dblcl, &elements[2], &elements[3]);
|
||||
printf("Add before: 0x%04x | ", elements[3].value);
|
||||
dbl_circ_list_print(demo_dblcl);
|
||||
|
||||
/* Remove head */
|
||||
this = dbl_circ_list_head(demo_dblcl);
|
||||
printf("Rm head: (0x%04x) | ", this->value);
|
||||
dbl_circ_list_remove(demo_dblcl, this);
|
||||
dbl_circ_list_print(demo_dblcl);
|
||||
|
||||
/* Remove currently second element */
|
||||
this = ((demo_struct_t *)dbl_circ_list_head(demo_dblcl))->next;
|
||||
printf("Rm 2nd : (0x%04x) | ", this->value);
|
||||
dbl_circ_list_remove(demo_dblcl, this);
|
||||
dbl_circ_list_print(demo_dblcl);
|
||||
|
||||
/* Remove tail */
|
||||
this = dbl_circ_list_tail(demo_dblcl);
|
||||
printf("Rm tail: (0x%04x) | ", this->value);
|
||||
dbl_circ_list_remove(demo_dblcl, this);
|
||||
dbl_circ_list_print(demo_dblcl);
|
||||
|
||||
/* Remove last remaining element */
|
||||
this = dbl_circ_list_tail(demo_dblcl);
|
||||
printf("Rm last: (0x%04x) | ", this->value);
|
||||
dbl_circ_list_remove(demo_dblcl, this);
|
||||
dbl_circ_list_print(demo_dblcl);
|
||||
|
||||
printf("Circular, doubly-linked list is%s empty\n",
|
||||
dbl_circ_list_is_empty(demo_dblcl) ? "" : " not");
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
dbl_list_print(dbl_list_t dll)
|
||||
{
|
||||
demo_struct_t *this;
|
||||
|
||||
for(this = *dll; this != NULL; this = this->next) {
|
||||
printf("<--(");
|
||||
if(this->previous == NULL) {
|
||||
printf(" null ");
|
||||
} else {
|
||||
printf("0x%04x", this->previous->value);
|
||||
}
|
||||
|
||||
printf(")--0x%04x--(", this->value);
|
||||
|
||||
if(this->next == NULL) {
|
||||
printf(" null ");
|
||||
} else {
|
||||
printf("0x%04x", this->next->value);
|
||||
}
|
||||
printf(")-->");
|
||||
}
|
||||
|
||||
printf(" (Length=%lu)\n", dbl_list_length(dll));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
demonstrate_dbl_list(void)
|
||||
{
|
||||
int i;
|
||||
demo_struct_t *this;
|
||||
|
||||
dbl_list_init(demo_dbl);
|
||||
printf("==================\n");
|
||||
printf("Doubly-linked list\n");
|
||||
|
||||
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
|
||||
elements[i].next = NULL;
|
||||
elements[i].previous = NULL;
|
||||
}
|
||||
|
||||
/* Add elements */
|
||||
dbl_list_add_tail(demo_dbl, &elements[0]);
|
||||
printf("Add tail : 0x%04x | ", elements[0].value);
|
||||
dbl_list_print(demo_dbl);
|
||||
|
||||
dbl_list_add_after(demo_dbl, &elements[0], &elements[1]);
|
||||
printf("Add after : 0x%04x | ", elements[1].value);
|
||||
dbl_list_print(demo_dbl);
|
||||
|
||||
dbl_list_add_head(demo_dbl, &elements[2]);
|
||||
printf("Add head : 0x%04x | ", elements[2].value);
|
||||
dbl_list_print(demo_dbl);
|
||||
|
||||
dbl_list_add_before(demo_dbl, &elements[2], &elements[3]);
|
||||
printf("Add before: 0x%04x | ", elements[3].value);
|
||||
dbl_list_print(demo_dbl);
|
||||
|
||||
/* Remove head */
|
||||
this = dbl_list_head(demo_dbl);
|
||||
printf("Rm head: (0x%04x) | ", this->value);
|
||||
dbl_list_remove(demo_dbl, this);
|
||||
dbl_list_print(demo_dbl);
|
||||
|
||||
/* Remove currently second element */
|
||||
this = ((demo_struct_t *)dbl_list_head(demo_dbl))->next;
|
||||
printf("Rm 2nd : (0x%04x) | ", this->value);
|
||||
dbl_list_remove(demo_dbl, this);
|
||||
dbl_list_print(demo_dbl);
|
||||
|
||||
/* Remove tail */
|
||||
this = dbl_list_tail(demo_dbl);
|
||||
printf("Rm tail: (0x%04x) | ", this->value);
|
||||
dbl_list_remove(demo_dbl, this);
|
||||
dbl_list_print(demo_dbl);
|
||||
|
||||
/* Remove last remaining element */
|
||||
this = dbl_list_tail(demo_dbl);
|
||||
printf("Rm last: (0x%04x) | ", this->value);
|
||||
dbl_list_remove(demo_dbl, this);
|
||||
dbl_list_print(demo_dbl);
|
||||
|
||||
printf("Doubly-linked list is%s empty\n",
|
||||
dbl_list_is_empty(demo_dbl) ? "" : " not");
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
circular_list_print(circular_list_t cl)
|
||||
{
|
||||
demo_struct_t *this = *cl;
|
||||
|
||||
if(*cl == NULL) {
|
||||
printf("Length=0\n");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
printf("0x%04x-->", this->value);
|
||||
this = this->next;
|
||||
} while(this != *cl);
|
||||
|
||||
printf("0x%04x (Length=%lu)\n", this->value, circular_list_length(cl));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
demonstrate_circular_list(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
circular_list_init(demo_cll);
|
||||
printf("============================\n");
|
||||
printf("Circular, singly-linked list\n");
|
||||
|
||||
/* Add elements */
|
||||
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
|
||||
elements[i].next = NULL;
|
||||
circular_list_add(demo_cll, &elements[i]);
|
||||
|
||||
printf("Add: 0x%04x | ", elements[i].value);
|
||||
circular_list_print(demo_cll);
|
||||
}
|
||||
|
||||
/* Remove head */
|
||||
circular_list_remove(demo_cll, circular_list_head(demo_cll));
|
||||
printf("Remove head | ");
|
||||
circular_list_print(demo_cll);
|
||||
|
||||
/* Remove currently second element */
|
||||
circular_list_remove(demo_cll,
|
||||
((demo_struct_t *)circular_list_head(demo_cll))->next);
|
||||
printf("Remove 2nd | ");
|
||||
circular_list_print(demo_cll);
|
||||
|
||||
/* Remove tail */
|
||||
circular_list_remove(demo_cll, circular_list_tail(demo_cll));
|
||||
printf("Remove tail | ");
|
||||
circular_list_print(demo_cll);
|
||||
|
||||
/* Remove last remaining element */
|
||||
circular_list_remove(demo_cll, circular_list_tail(demo_cll));
|
||||
printf("Remove last | ");
|
||||
circular_list_print(demo_cll);
|
||||
|
||||
printf("Circular list is%s empty\n",
|
||||
circular_list_is_empty(demo_cll) ? "" : " not");
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
demonstrate_stack(void)
|
||||
{
|
||||
int i;
|
||||
demo_struct_t *this;
|
||||
|
||||
printf("=====\n");
|
||||
printf("Stack\n");
|
||||
|
||||
stack_init(demo_stack);
|
||||
|
||||
/* Add elements */
|
||||
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
|
||||
elements[i].next = NULL;
|
||||
stack_push(demo_stack, &elements[i]);
|
||||
printf("Push: 0x%04x\n", elements[i].value);
|
||||
}
|
||||
|
||||
printf("Peek: 0x%04x\n",
|
||||
((demo_struct_t *)stack_peek(demo_stack))->value);
|
||||
|
||||
for(i = 0; i <= DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
|
||||
this = stack_pop(demo_stack);
|
||||
printf("Pop: ");
|
||||
if(this == NULL) {
|
||||
printf("(stack underflow)\n");
|
||||
} else {
|
||||
printf("0x%04x\n", this->value);
|
||||
}
|
||||
}
|
||||
printf("Stack is%s empty\n",
|
||||
stack_is_empty(demo_stack) ? "" : " not");
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
demonstrate_queue(void)
|
||||
{
|
||||
int i;
|
||||
demo_struct_t *this;
|
||||
|
||||
printf("=====\n");
|
||||
printf("Queue\n");
|
||||
|
||||
queue_init(demo_queue);
|
||||
|
||||
/* Add elements */
|
||||
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
|
||||
elements[i].next = NULL;
|
||||
queue_enqueue(demo_queue, &elements[i]);
|
||||
printf("Enqueue: 0x%04x\n", elements[i].value);
|
||||
}
|
||||
|
||||
printf("Peek: 0x%04x\n",
|
||||
((demo_struct_t *)queue_peek(demo_queue))->value);
|
||||
|
||||
for(i = 0; i <= DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
|
||||
this = queue_dequeue(demo_queue);
|
||||
printf("Dequeue: ");
|
||||
if(this == NULL) {
|
||||
printf("(queue underflow)\n");
|
||||
} else {
|
||||
printf("0x%04lx\n", (unsigned long)this->value);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Queue is%s empty\n",
|
||||
queue_is_empty(demo_queue) ? "" : " not");
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(data_structure_process, ev, data)
|
||||
{
|
||||
int i;
|
||||
|
||||
PROCESS_BEGIN();
|
||||
|
||||
/* Generate some elements */
|
||||
printf("Elements: [");
|
||||
|
||||
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
|
||||
elements[i].next = NULL;
|
||||
elements[i].value = random_rand();
|
||||
printf(" 0x%04x", elements[i].value);
|
||||
}
|
||||
printf(" ]\n");
|
||||
|
||||
demonstrate_stack();
|
||||
demonstrate_queue();
|
||||
demonstrate_circular_list();
|
||||
demonstrate_dbl_list();
|
||||
demonstrate_dbl_circ_list();
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
157
os/lib/circular-list.c
Normal file
157
os/lib/circular-list.c
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
|
||||
* Copyright (c) 2017, James Pope
|
||||
* 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.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \addtogroup circular-singly-linked-list
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
* Implementation of circular singly linked lists
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
#include "lib/circular-list.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct cl {
|
||||
struct cl *next;
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
circular_list_init(circular_list_t cl)
|
||||
{
|
||||
*cl = NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void *
|
||||
circular_list_head(circular_list_t cl)
|
||||
{
|
||||
return *cl;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void *
|
||||
circular_list_tail(circular_list_t cl)
|
||||
{
|
||||
struct cl *this;
|
||||
|
||||
if(*cl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(this = *cl; this->next != *cl; this = this->next);
|
||||
|
||||
return this;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
circular_list_remove(circular_list_t cl, void *element)
|
||||
{
|
||||
struct cl *this, *previous;
|
||||
|
||||
if(*cl == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We start traversing from the second element.
|
||||
* The head will be visited last. We always update the list's head after
|
||||
* removal, just in case we have just removed the head.
|
||||
*/
|
||||
previous = *cl;
|
||||
this = previous->next;
|
||||
|
||||
do {
|
||||
if(this == element) {
|
||||
previous->next = this->next;
|
||||
*cl = this->next == this ? NULL : previous;
|
||||
return;
|
||||
}
|
||||
previous = this;
|
||||
this = this->next;
|
||||
} while(this != ((struct cl *)*cl)->next);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
circular_list_add(circular_list_t cl, void *element)
|
||||
{
|
||||
struct cl *head;
|
||||
|
||||
if(element == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't add twice */
|
||||
circular_list_remove(cl, element);
|
||||
|
||||
head = *cl;
|
||||
|
||||
if(head == NULL) {
|
||||
/* If the list was empty, we update the new element to point to itself */
|
||||
((struct cl *)element)->next = element;
|
||||
} else {
|
||||
/* If the list exists, we add the new element between the current head and
|
||||
* the previously second element. */
|
||||
((struct cl *)element)->next = head->next;
|
||||
head->next = element;
|
||||
}
|
||||
|
||||
/* In all cases, the new element becomes the list's new head */
|
||||
*cl = element;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned long
|
||||
circular_list_length(circular_list_t cl)
|
||||
{
|
||||
unsigned long len = 1;
|
||||
struct cl *this;
|
||||
|
||||
if(circular_list_is_empty(cl)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(this = *cl; this->next != *cl; this = this->next) {
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
circular_list_is_empty(circular_list_t cl)
|
||||
{
|
||||
return *cl == NULL ? true : false;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
155
os/lib/circular-list.h
Normal file
155
os/lib/circular-list.h
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
|
||||
* Copyright (c) 2017, James Pope
|
||||
* 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.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** \addtogroup data
|
||||
* @{
|
||||
*
|
||||
* \defgroup circular-singly-linked-list Circular, singly-linked list
|
||||
*
|
||||
* This library provides functions for the creation and manipulation of
|
||||
* circular, singly-linked lists.
|
||||
*
|
||||
* A circular, singly-linked list is declared using the CIRCULAR_LIST macro.
|
||||
* Elements must be allocated by the calling code and must be of a C struct
|
||||
* datatype. In this struct, the first field must be a pointer called \e next.
|
||||
* This field will be used by the library to maintain the list. Application
|
||||
* code must not modify this field directly.
|
||||
*
|
||||
* Functions that modify the list (add / remove) will, in the general case,
|
||||
* update the list's head and item order. If you call one of these functions
|
||||
* as part of a list traversal, it is advised to stop / restart traversing
|
||||
* after the respective function returns.
|
||||
* @{
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifndef CIRCULAR_LIST_H_
|
||||
#define CIRCULAR_LIST_H_
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Define a circular, singly-linked list.
|
||||
*
|
||||
* This macro defines a circular, singly-linked list.
|
||||
*
|
||||
* The datatype for elements must be a C struct. The struct's first member must
|
||||
* be a pointer called \e next. This is used internally by the library to
|
||||
* maintain data structure integrity and must not be modified directly by
|
||||
* application code.
|
||||
*
|
||||
* \param name The name of the circular, singly-linked list.
|
||||
*/
|
||||
#define CIRCULAR_LIST(name) \
|
||||
static void *name##_circular_list = NULL; \
|
||||
static circular_list_t name = (circular_list_t)&name##_circular_list
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief The circular, singly-linked list datatype
|
||||
*/
|
||||
typedef void **circular_list_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Initialise a circular, singly-linked list.
|
||||
* \param cl The circular, singly-linked list.
|
||||
*/
|
||||
void circular_list_init(circular_list_t cl);
|
||||
|
||||
/**
|
||||
* \brief Return the tail of a circular, singly-linked list.
|
||||
* \param cl The circular, singly-linked list.
|
||||
* \return A pointer to the list's head, or NULL if the list is empty
|
||||
*/
|
||||
void *circular_list_head(circular_list_t cl);
|
||||
|
||||
/**
|
||||
* \brief Return the tail of a circular, singly-linked list.
|
||||
* \param cl The circular, singly-linked list.
|
||||
* \return A pointer to the list's tail, or NULL if the list is empty
|
||||
*/
|
||||
void *circular_list_tail(circular_list_t cl);
|
||||
|
||||
/**
|
||||
* \brief Add an element to a circular, singly-linked list.
|
||||
* \param cl The circular, singly-linked list.
|
||||
* \param element A pointer to the element to be added.
|
||||
*
|
||||
* The caller should make no assumptions as to the position in the list of the
|
||||
* new element.
|
||||
*
|
||||
* After this function returns, the list's head is not guaranteed to be the
|
||||
* same as it was before the addition.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void circular_list_add(circular_list_t cl, void *element);
|
||||
|
||||
/**
|
||||
* \brief Remove an element from a circular, singly-linked list.
|
||||
* \param cl The circular, singly-linked list.
|
||||
* \param element A pointer to the element to be removed.
|
||||
*
|
||||
* After this function returns, the list's head is not guaranteed to be the
|
||||
* same as it was before the addition.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void circular_list_remove(circular_list_t cl, void *element);
|
||||
|
||||
/**
|
||||
* \brief Get the length of a circular, singly-linked list.
|
||||
* \param cl The circular, singly-linked list.
|
||||
* \return The number of elements in the list
|
||||
*/
|
||||
unsigned long circular_list_length(circular_list_t cl);
|
||||
|
||||
/**
|
||||
* \brief Determine whether a circular, singly-linked list is empty.
|
||||
* \param cl The circular, singly-linked list.
|
||||
* \retval true The list is empty
|
||||
* \retval false The list is not empty
|
||||
*/
|
||||
bool circular_list_is_empty(circular_list_t cl);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* CIRCULAR_LIST_H_ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
227
os/lib/dbl-circ-list.c
Normal file
227
os/lib/dbl-circ-list.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
|
||||
* Copyright (c) 2017, James Pope
|
||||
* 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.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \addtogroup doubly-linked-circular-list
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
* Implementation of circular, doubly-linked lists
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
#include "lib/dbl-circ-list.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct dblcl {
|
||||
struct dblcl *next;
|
||||
struct dblcl *previous;
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_circ_list_init(dbl_circ_list_t dblcl)
|
||||
{
|
||||
*dblcl = NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void *
|
||||
dbl_circ_list_head(dbl_circ_list_t dblcl)
|
||||
{
|
||||
return *dblcl;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void *
|
||||
dbl_circ_list_tail(dbl_circ_list_t dblcl)
|
||||
{
|
||||
struct dblcl *this;
|
||||
|
||||
if(*dblcl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(this = *dblcl; this->next != *dblcl; this = this->next);
|
||||
|
||||
return this;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_circ_list_remove(dbl_circ_list_t dblcl, void *element)
|
||||
{
|
||||
struct dblcl *this;
|
||||
|
||||
if(*dblcl == NULL || element == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
this = *dblcl;
|
||||
|
||||
do {
|
||||
if(this == element) {
|
||||
this->previous->next = this->next;
|
||||
this->next->previous = this->previous;
|
||||
|
||||
/* We need to update the head of the list if we removed the head */
|
||||
if(*dblcl == element) {
|
||||
*dblcl = this->next == this ? NULL : this->next;
|
||||
}
|
||||
|
||||
this->next = NULL;
|
||||
this->previous = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this = this->next;
|
||||
} while(this != *dblcl);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_circ_list_add_head(dbl_circ_list_t dblcl, void *element)
|
||||
{
|
||||
struct dblcl *head;
|
||||
|
||||
if(element == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't add twice */
|
||||
dbl_circ_list_remove(dblcl, element);
|
||||
|
||||
head = dbl_circ_list_head(dblcl);
|
||||
|
||||
if(head == NULL) {
|
||||
/* If the list was empty */
|
||||
((struct dblcl *)element)->next = element;
|
||||
((struct dblcl *)element)->previous = element;
|
||||
} else {
|
||||
/* If the list was not empty */
|
||||
((struct dblcl *)element)->next = head;
|
||||
((struct dblcl *)element)->previous = head->previous;
|
||||
head->previous->next = element;
|
||||
head->previous = element;
|
||||
}
|
||||
|
||||
*dblcl = element;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_circ_list_add_tail(dbl_circ_list_t dblcl, void *element)
|
||||
{
|
||||
struct dblcl *tail;
|
||||
|
||||
if(element == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't add twice */
|
||||
dbl_circ_list_remove(dblcl, element);
|
||||
|
||||
tail = dbl_circ_list_tail(dblcl);
|
||||
|
||||
if(tail == NULL) {
|
||||
/* If the list was empty */
|
||||
((struct dblcl *)element)->next = element;
|
||||
((struct dblcl *)element)->previous = element;
|
||||
*dblcl = element;
|
||||
} else {
|
||||
/* If the list was not empty */
|
||||
((struct dblcl *)element)->next = *dblcl;
|
||||
((struct dblcl *)element)->previous = tail;
|
||||
tail->next->previous = element;
|
||||
tail->next = element;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_circ_list_add_after(dbl_circ_list_t dblcl, void *existing, void *element)
|
||||
{
|
||||
if(element == NULL || existing == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't add twice */
|
||||
dbl_circ_list_remove(dblcl, element);
|
||||
|
||||
((struct dblcl *)element)->next = ((struct dblcl *)existing)->next;
|
||||
((struct dblcl *)element)->previous = existing;
|
||||
((struct dblcl *)existing)->next->previous = element;
|
||||
((struct dblcl *)existing)->next = element;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_circ_list_add_before(dbl_circ_list_t dblcl, void *existing, void *element)
|
||||
{
|
||||
if(element == NULL || existing == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't add twice */
|
||||
dbl_circ_list_remove(dblcl, element);
|
||||
|
||||
((struct dblcl *)element)->next = existing;
|
||||
((struct dblcl *)element)->previous = ((struct dblcl *)existing)->previous;
|
||||
((struct dblcl *)existing)->previous->next = element;
|
||||
((struct dblcl *)existing)->previous = element;
|
||||
|
||||
/* If we added before the list's head, we must update the head */
|
||||
if(*dblcl == existing) {
|
||||
*dblcl = element;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned long
|
||||
dbl_circ_list_length(dbl_circ_list_t dblcl)
|
||||
{
|
||||
unsigned long len = 1;
|
||||
struct dblcl *this;
|
||||
|
||||
if(*dblcl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(this = *dblcl; this->next != *dblcl; this = this->next) {
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
dbl_circ_list_is_empty(dbl_circ_list_t dblcl)
|
||||
{
|
||||
return *dblcl == NULL ? true : false;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
193
os/lib/dbl-circ-list.h
Normal file
193
os/lib/dbl-circ-list.h
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
|
||||
* Copyright (c) 2017, James Pope
|
||||
* 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.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** \addtogroup data
|
||||
* @{
|
||||
*
|
||||
* \defgroup doubly-linked-circular-list Circular, doubly-linked list
|
||||
*
|
||||
* This library provides functions for the creation and manipulation of
|
||||
* circular, doubly-linked lists.
|
||||
*
|
||||
* A circular, doubly-linked list is declared using the DBL_CIRC_LIST macro.
|
||||
* Elements must be allocated by the calling code and must be of a C struct
|
||||
* datatype. In this struct, the first field must be a pointer called \e next.
|
||||
* The second field must be a pointer called \e previous.
|
||||
* These fields will be used by the library to maintain the list. Application
|
||||
* code must not modify these fields directly.
|
||||
*
|
||||
* Functions that modify the list (add / remove) will, in the general case,
|
||||
* update the list's head and item order. If you call one of these functions
|
||||
* as part of a list traversal, it is advised to stop / restart traversing
|
||||
* after the respective function returns.
|
||||
* @{
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifndef DBL_CIRC_LIST_H_
|
||||
#define DBL_CIRC_LIST_H_
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Define a circular, doubly-linked list.
|
||||
*
|
||||
* This macro defines a circular, doubly-linked list.
|
||||
*
|
||||
* The datatype for elements must be a C struct.
|
||||
* The struct's first member must be a pointer called \e next.
|
||||
* The second field must be a pointer called \e previous.
|
||||
* These fields will be used by the library to maintain the list. Application
|
||||
* code must not modify these fields directly.
|
||||
*
|
||||
* \param name The name of the circular, doubly-linked list.
|
||||
*/
|
||||
#define DBL_CIRC_LIST(name) \
|
||||
static void *name##_dbl_circ_list = NULL; \
|
||||
static dbl_list_t name = (dbl_circ_list_t)&name##_dbl_circ_list
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief The doubly-linked list datatype
|
||||
*/
|
||||
typedef void **dbl_circ_list_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Initialise a circular, doubly-linked list.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
*/
|
||||
void dbl_circ_list_init(dbl_circ_list_t dblcl);
|
||||
|
||||
/**
|
||||
* \brief Return the tail of a circular, doubly-linked list.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
* \return A pointer to the list's head, or NULL if the list is empty
|
||||
*/
|
||||
void *dbl_circ_list_head(dbl_circ_list_t dblcl);
|
||||
|
||||
/**
|
||||
* \brief Return the tail of a circular, doubly-linked list.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
* \return A pointer to the list's tail, or NULL if the list is empty
|
||||
*/
|
||||
void *dbl_circ_list_tail(dbl_circ_list_t dblcl);
|
||||
|
||||
/**
|
||||
* \brief Add an element to the head of a circular, doubly-linked list.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
* \param element A pointer to the element to be added.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_circ_list_add_head(dbl_circ_list_t dblcl, void *element);
|
||||
|
||||
/**
|
||||
* \brief Add an element to the tail of a circular, doubly-linked list.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
* \param element A pointer to the element to be added.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_circ_list_add_tail(dbl_circ_list_t dblcl, void *element);
|
||||
|
||||
/**
|
||||
* \brief Add an element to a circular, doubly linked list after an existing element.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
* \param existing A pointer to the existing element.
|
||||
* \param element A pointer to the element to be added.
|
||||
*
|
||||
* This function will add \e element after \e existing
|
||||
*
|
||||
* The function will not verify that \e existing is already part of the list.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_circ_list_add_after(dbl_circ_list_t dblcl, void *existing,
|
||||
void *element);
|
||||
|
||||
/**
|
||||
* \brief Add an element to a circular, doubly linked list before an existing element.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
* \param existing A pointer to the existing element.
|
||||
* \param element A pointer to the element to be added.
|
||||
*
|
||||
* This function will add \e element before \e existing
|
||||
*
|
||||
* The function will not verify that \e existing is already part of the list.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_circ_list_add_before(dbl_circ_list_t dblcl, void *existing,
|
||||
void *element);
|
||||
|
||||
/**
|
||||
* \brief Remove an element from a circular, doubly-linked list.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
* \param element A pointer to the element to be removed.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_circ_list_remove(dbl_circ_list_t dblcl, void *element);
|
||||
|
||||
/**
|
||||
* \brief Get the length of a circular, doubly-linked list.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
* \return The number of elements in the list
|
||||
*/
|
||||
unsigned long dbl_circ_list_length(dbl_circ_list_t dblcl);
|
||||
|
||||
/**
|
||||
* \brief Determine whether a circular, doubly-linked list is empty.
|
||||
* \param dblcl The circular, doubly-linked list.
|
||||
* \retval true The list is empty
|
||||
* \retval false The list is not empty
|
||||
*/
|
||||
bool dbl_circ_list_is_empty(dbl_circ_list_t dblcl);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* DBL_CIRC_LIST_H_ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
226
os/lib/dbl-list.c
Normal file
226
os/lib/dbl-list.c
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
|
||||
* Copyright (c) 2017, James Pope
|
||||
* 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.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \addtogroup doubly-linked-list
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
* Implementation of doubly-linked lists
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
#include "lib/dbl-list.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct dll {
|
||||
struct dll *next;
|
||||
struct dll *previous;
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_list_init(dbl_list_t dll)
|
||||
{
|
||||
*dll = NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void *
|
||||
dbl_list_head(dbl_list_t dll)
|
||||
{
|
||||
return *dll;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void *
|
||||
dbl_list_tail(dbl_list_t dll)
|
||||
{
|
||||
struct dll *this;
|
||||
|
||||
if(*dll == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(this = *dll; this->next != NULL; this = this->next);
|
||||
|
||||
return this;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_list_remove(dbl_list_t dll, void *element)
|
||||
{
|
||||
struct dll *this, *previous, *next;
|
||||
|
||||
if(*dll == NULL || element == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(this = *dll; this != NULL; this = this->next) {
|
||||
if(this == element) {
|
||||
previous = this->previous;
|
||||
next = this->next;
|
||||
|
||||
if(previous) {
|
||||
previous->next = this->next;
|
||||
}
|
||||
|
||||
if(next) {
|
||||
next->previous = this->previous;
|
||||
}
|
||||
|
||||
if(*dll == this) {
|
||||
*dll = next;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_list_add_head(dbl_list_t dll, void *element)
|
||||
{
|
||||
struct dll *head;
|
||||
|
||||
if(element == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't add twice */
|
||||
dbl_list_remove(dll, element);
|
||||
|
||||
head = dbl_list_head(dll);
|
||||
|
||||
((struct dll *)element)->previous = NULL;
|
||||
((struct dll *)element)->next = head;
|
||||
|
||||
if(head) {
|
||||
/* If the list was not empty, update ->previous on the old head */
|
||||
head->previous = element;
|
||||
}
|
||||
|
||||
*dll = element;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_list_add_tail(dbl_list_t dll, void *element)
|
||||
{
|
||||
struct dll *tail;
|
||||
|
||||
if(element == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't add twice */
|
||||
dbl_list_remove(dll, element);
|
||||
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
if(tail == NULL) {
|
||||
/* The list was empty */
|
||||
*dll = element;
|
||||
} else {
|
||||
tail->next = element;
|
||||
}
|
||||
|
||||
((struct dll *)element)->previous = tail;
|
||||
((struct dll *)element)->next = NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_list_add_after(dbl_list_t dll, void *existing, void *element)
|
||||
{
|
||||
if(element == NULL || existing == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't add twice */
|
||||
dbl_list_remove(dll, element);
|
||||
|
||||
((struct dll *)element)->next = ((struct dll *)existing)->next;
|
||||
((struct dll *)element)->previous = existing;
|
||||
|
||||
if(((struct dll *)existing)->next) {
|
||||
((struct dll *)existing)->next->previous = element;
|
||||
}
|
||||
((struct dll *)existing)->next = element;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
dbl_list_add_before(dbl_list_t dll, void *existing, void *element)
|
||||
{
|
||||
if(element == NULL || existing == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't add twice */
|
||||
dbl_list_remove(dll, element);
|
||||
|
||||
((struct dll *)element)->next = existing;
|
||||
((struct dll *)element)->previous = ((struct dll *)existing)->previous;
|
||||
|
||||
if(((struct dll *)existing)->previous) {
|
||||
((struct dll *)existing)->previous->next = element;
|
||||
}
|
||||
((struct dll *)existing)->previous = element;
|
||||
|
||||
/* If we added before the list's head, we must update the head */
|
||||
if(*dll == existing) {
|
||||
*dll = element;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
unsigned long
|
||||
dbl_list_length(dbl_list_t dll)
|
||||
{
|
||||
unsigned long len = 0;
|
||||
struct dll *this;
|
||||
|
||||
if(*dll == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(this = *dll; this != NULL; this = this->next) {
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool
|
||||
dbl_list_is_empty(dbl_list_t dll)
|
||||
{
|
||||
return *dll == NULL ? true : false;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
191
os/lib/dbl-list.h
Normal file
191
os/lib/dbl-list.h
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
|
||||
* Copyright (c) 2017, James Pope
|
||||
* 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.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** \addtogroup data
|
||||
* @{
|
||||
*
|
||||
* \defgroup doubly-linked-list Doubly-linked list
|
||||
*
|
||||
* This library provides functions for the creation and manipulation of
|
||||
* doubly-linked lists.
|
||||
*
|
||||
* A doubly-linked list is declared using the DBL_LIST macro.
|
||||
* Elements must be allocated by the calling code and must be of a C struct
|
||||
* datatype. In this struct, the first field must be a pointer called \e next.
|
||||
* The second field must be a pointer called \e previous.
|
||||
* These fields will be used by the library to maintain the list. Application
|
||||
* code must not modify these fields directly.
|
||||
*
|
||||
* Functions that modify the list (add / remove) will, in the general case,
|
||||
* update the list's head and item order. If you call one of these functions
|
||||
* as part of a list traversal, it is advised to stop / restart traversing
|
||||
* after the respective function returns.
|
||||
* @{
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifndef DBL_LIST_H_
|
||||
#define DBL_LIST_H_
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Define a doubly-linked list.
|
||||
*
|
||||
* This macro defines a doubly-linked list.
|
||||
*
|
||||
* The datatype for elements must be a C struct.
|
||||
* The struct's first member must be a pointer called \e next.
|
||||
* The second field must be a pointer called \e previous.
|
||||
* These fields will be used by the library to maintain the list. Application
|
||||
* code must not modify these fields directly.
|
||||
*
|
||||
* \param name The name of the doubly-linked list.
|
||||
*/
|
||||
#define DBL_LIST(name) \
|
||||
static void *name##_dbl_list = NULL; \
|
||||
static dbl_list_t name = (dbl_list_t)&name##_dbl_list
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief The doubly-linked list datatype
|
||||
*/
|
||||
typedef void **dbl_list_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Initialise a doubly-linked list.
|
||||
* \param dll The doubly-linked list.
|
||||
*/
|
||||
void dbl_list_init(dbl_list_t dll);
|
||||
|
||||
/**
|
||||
* \brief Return the tail of a doubly-linked list.
|
||||
* \param dll The doubly-linked list.
|
||||
* \return A pointer to the list's head, or NULL if the list is empty
|
||||
*/
|
||||
void *dbl_list_head(dbl_list_t dll);
|
||||
|
||||
/**
|
||||
* \brief Return the tail of a doubly-linked list.
|
||||
* \param dll The doubly-linked list.
|
||||
* \return A pointer to the list's tail, or NULL if the list is empty
|
||||
*/
|
||||
void *dbl_list_tail(dbl_list_t dll);
|
||||
|
||||
/**
|
||||
* \brief Add an element to the head of a doubly-linked list.
|
||||
* \param dll The doubly-linked list.
|
||||
* \param element A pointer to the element to be added.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_list_add_head(dbl_list_t dll, void *element);
|
||||
|
||||
/**
|
||||
* \brief Add an element to the tail of a doubly-linked list.
|
||||
* \param dll The doubly-linked list.
|
||||
* \param element A pointer to the element to be added.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_list_add_tail(dbl_list_t dll, void *element);
|
||||
|
||||
/**
|
||||
* \brief Add an element to a doubly linked list after an existing element.
|
||||
* \param dll The doubly-linked list.
|
||||
* \param existing A pointer to the existing element.
|
||||
* \param element A pointer to the element to be added.
|
||||
*
|
||||
* This function will add \e element after \e existing
|
||||
*
|
||||
* The function will not verify that \e existing is already part of the list.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_list_add_after(dbl_list_t dll, void *existing, void *element);
|
||||
|
||||
/**
|
||||
* \brief Add an element to a doubly linked list before an existing element.
|
||||
* \param dll The doubly-linked list.
|
||||
* \param existing A pointer to the existing element.
|
||||
* \param element A pointer to the element to be added.
|
||||
*
|
||||
* This function will add \e element before \e existing
|
||||
*
|
||||
* The function will not verify that \e existing is already part of the list.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_list_add_before(dbl_list_t dll, void *existing, void *element);
|
||||
|
||||
/**
|
||||
* \brief Remove an element from a doubly-linked list.
|
||||
* \param dll The doubly-linked list.
|
||||
* \param element A pointer to the element to be removed.
|
||||
*
|
||||
* Calling this function will update the list's head and item order. If you
|
||||
* call this function as part of a list traversal, it is advised to stop
|
||||
* traversing after this function returns.
|
||||
*/
|
||||
void dbl_list_remove(dbl_list_t dll, void *element);
|
||||
|
||||
/**
|
||||
* \brief Get the length of a doubly-linked list.
|
||||
* \param dll The doubly-linked list.
|
||||
* \return The number of elements in the list
|
||||
*/
|
||||
unsigned long dbl_list_length(dbl_list_t dll);
|
||||
|
||||
/**
|
||||
* \brief Determine whether a doubly-linked list is empty.
|
||||
* \param dll The doubly-linked list.
|
||||
* \retval true The list is empty
|
||||
* \retval false The list is not empty
|
||||
*/
|
||||
bool dbl_list_is_empty(dbl_list_t dll);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* DBL_LIST_H_ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
143
os/lib/queue.h
Normal file
143
os/lib/queue.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
|
||||
* Copyright (c) 2017, James Pope
|
||||
* 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.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \addtogroup data
|
||||
* @{
|
||||
*
|
||||
* \defgroup queue Queue library
|
||||
*
|
||||
* This library provides functions for the creation and manipulation of
|
||||
* queues. The library is implemented as a wrapper around the list library.
|
||||
*
|
||||
* A queue is declared using the QUEUE macro. Queue elements must be
|
||||
* allocated by the calling code and must be of a C struct datatype. In this
|
||||
* struct, the first field must be a pointer called \e next. This field will
|
||||
* be used by the library to maintain the queue. Application code must not
|
||||
* modify this field directly.
|
||||
* @{
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifndef QUEUE_H_
|
||||
#define QUEUE_H_
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
#include "lib/list.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief The queue data type
|
||||
*/
|
||||
typedef list_t queue_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Define a queue.
|
||||
*
|
||||
* This macro defines a queue.
|
||||
*
|
||||
* The datatype for elements must be a C struct. The struct's first member must
|
||||
* be a pointer called \e next. This is used internally by the library to
|
||||
* maintain data structure integrity and must not be modified directly by
|
||||
* application code.
|
||||
*
|
||||
* \param name The name of the queue.
|
||||
*/
|
||||
#define QUEUE(name) LIST(name)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct queue {
|
||||
struct queue *next;
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Initialise a queue
|
||||
* \param queue The queue
|
||||
*/
|
||||
static inline void
|
||||
queue_init(queue_t queue)
|
||||
{
|
||||
list_init(queue);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Adds an element to the tail of the queue
|
||||
* \param queue The queue
|
||||
* \param element A pointer to the element to be added
|
||||
*/
|
||||
static inline void
|
||||
queue_enqueue(queue_t queue, void *element)
|
||||
{
|
||||
list_add(queue, element);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Removes the element at the front of the queue
|
||||
* \param queue The queue
|
||||
* \return A pointer to the element removed
|
||||
*
|
||||
* If this function returns NULL if the queue was empty (queue underflow)
|
||||
*/
|
||||
static inline void *
|
||||
queue_dequeue(queue_t queue)
|
||||
{
|
||||
return list_pop(queue);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Returns the front element of the queue, without removing it
|
||||
* \param queue The queue
|
||||
* \return A pointer to the element at the front of the queue
|
||||
*/
|
||||
static inline void *
|
||||
queue_peek(queue_t queue)
|
||||
{
|
||||
return list_head(queue);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Check if a queue is empty
|
||||
* \param queue The queue
|
||||
* \retval true The queue is empty
|
||||
* \retval false The queue has at least one element
|
||||
*/
|
||||
static inline bool
|
||||
queue_is_empty(queue_t queue)
|
||||
{
|
||||
return *queue == NULL ? true : false;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* QUEUE_H_ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
143
os/lib/stack.h
Normal file
143
os/lib/stack.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
|
||||
* Copyright (c) 2017, James Pope
|
||||
* 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.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \addtogroup data
|
||||
* @{
|
||||
*
|
||||
* \defgroup stack-data-structure Stack library
|
||||
*
|
||||
* This library provides functions for the creation and manipulation of
|
||||
* stacks. The library is implemented as a wrapper around the list library.
|
||||
*
|
||||
* A stack is declared using the STACK macro. Stack elements must be
|
||||
* allocated by the calling code and must be of a C struct datatype. In this
|
||||
* struct, the first field must be a pointer called \e next. This field will
|
||||
* be used by the library to maintain the stack. Application code must not
|
||||
* modify this field directly.
|
||||
* @{
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifndef STACK_H_
|
||||
#define STACK_H_
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
#include "lib/list.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief The stack data type
|
||||
*/
|
||||
typedef list_t stack_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Define a stack.
|
||||
*
|
||||
* This macro defines a stack.
|
||||
*
|
||||
* The datatype for elements must be a C struct. The struct's first member must
|
||||
* be a pointer called \e next. This is used internally by the library to
|
||||
* maintain data structure integrity and must not be modified directly by
|
||||
* application code.
|
||||
*
|
||||
* \param name The name of the stack.
|
||||
*/
|
||||
#define STACK(name) LIST(name)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
struct stack {
|
||||
struct stack *next;
|
||||
};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Initialise a stack
|
||||
* \param stack The stack
|
||||
*/
|
||||
static inline void
|
||||
stack_init(stack_t stack)
|
||||
{
|
||||
list_init(stack);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Adds an element to the top of the stack
|
||||
* \param stack The stack
|
||||
* \param element A pointer to the element to be added
|
||||
*/
|
||||
static inline void
|
||||
stack_push(stack_t stack, void *element)
|
||||
{
|
||||
list_push(stack, element);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Removes the top element from the stack
|
||||
* \param stack The stack
|
||||
* \return A pointer to the element popped
|
||||
*
|
||||
* If this function returns NULL if the stack was empty (stack underflow)
|
||||
*/
|
||||
static inline void *
|
||||
stack_pop(stack_t stack)
|
||||
{
|
||||
return list_pop(stack);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Returns the top element of the stack, without popping it
|
||||
* \param stack The stack
|
||||
* \return A pointer to the element at the top of the stack
|
||||
*/
|
||||
static inline void *
|
||||
stack_peek(stack_t stack)
|
||||
{
|
||||
return list_head(stack);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Check if a stack is empty
|
||||
* \param stack The stack
|
||||
* \retval true The stack is empty
|
||||
* \retval false The stack has at least one element
|
||||
*/
|
||||
static inline bool
|
||||
stack_is_empty(stack_t stack)
|
||||
{
|
||||
return *stack == NULL ? true : false;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* STACK_H_ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
@ -46,7 +46,7 @@
|
||||
|
||||
/* sanity check for configured values */
|
||||
#define COAP_MAX_PACKET_SIZE (COAP_MAX_HEADER_SIZE + REST_MAX_CHUNK_SIZE)
|
||||
#if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_IPH_LEN - UIP_UDPH_LEN)
|
||||
#if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPH_LEN - UIP_UDPH_LEN)
|
||||
#error "UIP_CONF_BUFFER_SIZE too small for REST_MAX_CHUNK_SIZE"
|
||||
#endif
|
||||
|
||||
|
@ -229,7 +229,7 @@ icmp_input()
|
||||
|
||||
uip_process(UIP_UDP_SEND_CONN);
|
||||
|
||||
memcpy(&mcast_buf, uip_buf, uip_len);
|
||||
memcpy(&mcast_buf, &uip_buf[UIP_LLH_LEN], uip_len);
|
||||
mcast_len = uip_len;
|
||||
/* pass the packet to our uip_process to check if it is allowed to
|
||||
* accept this packet or not */
|
||||
@ -239,7 +239,7 @@ icmp_input()
|
||||
|
||||
uip_process(UIP_DATA);
|
||||
|
||||
memcpy(uip_buf, &mcast_buf, mcast_len);
|
||||
memcpy(&uip_buf[UIP_LLH_LEN], &mcast_buf, mcast_len);
|
||||
uip_len = mcast_len;
|
||||
/* Return the IP of the original Multicast sender */
|
||||
uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &src_ip);
|
||||
@ -257,7 +257,7 @@ icmp_input()
|
||||
static void
|
||||
mcast_fwd(void *p)
|
||||
{
|
||||
memcpy(uip_buf, &mcast_buf, mcast_len);
|
||||
memcpy(&uip_buf[UIP_LLH_LEN], &mcast_buf, mcast_len);
|
||||
uip_len = mcast_len;
|
||||
UIP_IP_BUF->ttl--;
|
||||
tcpip_output(NULL);
|
||||
@ -291,7 +291,7 @@ in()
|
||||
parent_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(parent_ipaddr);
|
||||
|
||||
if(parent_lladdr == NULL) {
|
||||
PRINTF("ESMRF: NO Parent exist \n");
|
||||
PRINTF("ESMRF: No Parent found\n");
|
||||
UIP_MCAST6_STATS_ADD(mcast_dropped);
|
||||
return UIP_MCAST6_DROP;
|
||||
}
|
||||
@ -309,6 +309,7 @@ in()
|
||||
|
||||
if(UIP_IP_BUF->ttl <= 1) {
|
||||
UIP_MCAST6_STATS_ADD(mcast_dropped);
|
||||
PRINTF("ESMRF: TTL too low\n");
|
||||
return UIP_MCAST6_DROP;
|
||||
}
|
||||
|
||||
@ -350,12 +351,14 @@ in()
|
||||
fwd_delay = fwd_delay * (1 + ((random_rand() >> 11) % fwd_spread));
|
||||
}
|
||||
|
||||
memcpy(&mcast_buf, uip_buf, uip_len);
|
||||
memcpy(&mcast_buf, &uip_buf[UIP_LLH_LEN], uip_len);
|
||||
mcast_len = uip_len;
|
||||
ctimer_set(&mcast_periodic, fwd_delay, mcast_fwd, NULL);
|
||||
}
|
||||
PRINTF("ESMRF: %u bytes: fwd in %u [%u]\n",
|
||||
uip_len, fwd_delay, fwd_spread);
|
||||
} else {
|
||||
PRINTF("ESMRF: Group unknown, dropping\n");
|
||||
}
|
||||
|
||||
/* Done with this packet unless we are a member of the mcast group */
|
||||
|
@ -1321,7 +1321,7 @@ static void
|
||||
out()
|
||||
{
|
||||
|
||||
if(uip_len + HBHO_TOTAL_LEN > UIP_BUFSIZE) {
|
||||
if(uip_len + HBHO_TOTAL_LEN > UIP_BUFSIZE - UIP_LLH_LEN) {
|
||||
PRINTF("ROLL TM: Multicast Out can not add HBHO. Packet too long\n");
|
||||
goto drop;
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ static uint8_t fwd_spread;
|
||||
static void
|
||||
mcast_fwd(void *p)
|
||||
{
|
||||
memcpy(uip_buf, &mcast_buf, mcast_len);
|
||||
memcpy(&uip_buf[UIP_LLH_LEN], &mcast_buf, mcast_len);
|
||||
uip_len = mcast_len;
|
||||
UIP_IP_BUF->ttl--;
|
||||
tcpip_output(NULL);
|
||||
@ -106,6 +106,7 @@ in()
|
||||
*/
|
||||
d = rpl_get_any_dag();
|
||||
if(!d) {
|
||||
PRINTF("SMRF: No DODAG\n");
|
||||
UIP_MCAST6_STATS_ADD(mcast_dropped);
|
||||
return UIP_MCAST6_DROP;
|
||||
}
|
||||
@ -115,6 +116,7 @@ in()
|
||||
parent_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(parent_ipaddr);
|
||||
|
||||
if(parent_lladdr == NULL) {
|
||||
PRINTF("SMRF: No Parent found\n");
|
||||
UIP_MCAST6_STATS_ADD(mcast_dropped);
|
||||
return UIP_MCAST6_DROP;
|
||||
}
|
||||
@ -132,6 +134,7 @@ in()
|
||||
|
||||
if(UIP_IP_BUF->ttl <= 1) {
|
||||
UIP_MCAST6_STATS_ADD(mcast_dropped);
|
||||
PRINTF("SMRF: TTL too low\n");
|
||||
return UIP_MCAST6_DROP;
|
||||
}
|
||||
|
||||
@ -173,12 +176,14 @@ in()
|
||||
fwd_delay = fwd_delay * (1 + ((random_rand() >> 11) % fwd_spread));
|
||||
}
|
||||
|
||||
memcpy(&mcast_buf, uip_buf, uip_len);
|
||||
memcpy(&mcast_buf, &uip_buf[UIP_LLH_LEN], uip_len);
|
||||
mcast_len = uip_len;
|
||||
ctimer_set(&mcast_periodic, fwd_delay, mcast_fwd, NULL);
|
||||
}
|
||||
PRINTF("SMRF: %u bytes: fwd in %u [%u]\n",
|
||||
uip_len, fwd_delay, fwd_spread);
|
||||
} else {
|
||||
PRINTF("SMRF: Group unknown, dropping\n");
|
||||
}
|
||||
|
||||
/* Done with this packet unless we are a member of the mcast group */
|
||||
|
@ -123,7 +123,7 @@
|
||||
/* NOTE: In the multiple-reassembly context there is only room for the header / first fragment */
|
||||
#define SICSLOWPAN_IP_BUF(buf) ((struct uip_ip_hdr *)buf)
|
||||
#define SICSLOWPAN_UDP_BUF(buf) ((struct uip_udp_hdr *)&buf[UIP_IPH_LEN])
|
||||
#define SICSLOWPAN_IPPAYLOAD_BUF(buf) (&buf[UIP_LLIPH_LEN])
|
||||
#define SICSLOWPAN_IPPAYLOAD_BUF(buf) (&buf[UIP_IPH_LEN])
|
||||
|
||||
|
||||
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||
|
@ -472,12 +472,7 @@ output_fallback(void)
|
||||
#ifdef UIP_FALLBACK_INTERFACE
|
||||
LOG_INFO("fallback: removing ext hdrs & setting proto %d %d\n",
|
||||
uip_ext_len, *((uint8_t *)UIP_IP_BUF + 40));
|
||||
if(uip_ext_len > 0) {
|
||||
uint8_t proto = *((uint8_t *)UIP_IP_BUF + 40);
|
||||
remove_ext_hdr();
|
||||
/* This should be copied from the ext header... */
|
||||
UIP_IP_BUF->proto = proto;
|
||||
}
|
||||
remove_ext_hdr();
|
||||
/* Inform the other end that the destination is not reachable. If it's
|
||||
* not informed routes might get lost unexpectedly until there's a need
|
||||
* to send a new packet to the peer */
|
||||
|
@ -238,12 +238,8 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
#if UIP_CONF_ROUTER
|
||||
/* need to pick a source that corresponds to this node */
|
||||
uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &tmp_ipaddr);
|
||||
#else
|
||||
uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &tmp_ipaddr);
|
||||
#endif
|
||||
}
|
||||
|
||||
UIP_ICMP_BUF->type = type;
|
||||
|
@ -523,6 +523,7 @@ uip_connect(const uip_ipaddr_t *ripaddr, uint16_t rport)
|
||||
void
|
||||
remove_ext_hdr(void)
|
||||
{
|
||||
int last_uip_ext_len;
|
||||
/* Remove ext header before TCP/UDP processing. */
|
||||
if(uip_ext_len > 0) {
|
||||
LOG_DBG("Cutting ext-header before processing (extlen: %d, uiplen: %d)\n",
|
||||
@ -532,15 +533,17 @@ remove_ext_hdr(void)
|
||||
uip_clear_buf();
|
||||
return;
|
||||
}
|
||||
memmove(((uint8_t *)UIP_TCP_BUF), (uint8_t *)UIP_TCP_BUF + uip_ext_len,
|
||||
uip_len - UIP_IPH_LEN - uip_ext_len);
|
||||
last_uip_ext_len = uip_ext_len;
|
||||
uip_ext_len = 0;
|
||||
UIP_IP_BUF->proto = UIP_EXT_BUF->next;
|
||||
memmove(((uint8_t *)UIP_TCP_BUF), (uint8_t *)UIP_TCP_BUF + last_uip_ext_len,
|
||||
uip_len - UIP_IPH_LEN - last_uip_ext_len);
|
||||
|
||||
uip_len -= uip_ext_len;
|
||||
uip_len -= last_uip_ext_len;
|
||||
|
||||
/* Update the IP length. */
|
||||
UIP_IP_BUF->len[0] = (uip_len - UIP_IPH_LEN) >> 8;
|
||||
UIP_IP_BUF->len[1] = (uip_len - UIP_IPH_LEN) & 0xff;
|
||||
uip_ext_len = 0;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -1494,7 +1497,6 @@ uip_process(uint8_t flag)
|
||||
udp_input:
|
||||
|
||||
remove_ext_hdr();
|
||||
UIP_IP_BUF->proto = UIP_PROTO_UDP;
|
||||
|
||||
LOG_INFO("Receiving UDP packet\n");
|
||||
|
||||
@ -1607,7 +1609,6 @@ uip_process(uint8_t flag)
|
||||
tcp_input:
|
||||
|
||||
remove_ext_hdr();
|
||||
UIP_IP_BUF->proto = UIP_PROTO_TCP;
|
||||
|
||||
UIP_STAT(++uip_stat.tcp.recv);
|
||||
LOG_INFO("Receiving TCP packet\n");
|
||||
|
@ -128,6 +128,6 @@ uipbuf_clr_attr_flag(uint16_t flag)
|
||||
uint16_t
|
||||
uipbuf_is_attr_flag(uint16_t flag)
|
||||
{
|
||||
return (uipbuf_attrs[UIPBUF_ATTR_FLAGS] & flag) > 0;
|
||||
return (uipbuf_attrs[UIPBUF_ATTR_FLAGS] & flag) == flag;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -35,33 +35,106 @@
|
||||
|
||||
#include "contiki.h"
|
||||
|
||||
/* Get the next header given the buffer - start indicates that this is
|
||||
start of the IPv6 header - needs to be set to 0 when in an ext hdr */
|
||||
|
||||
/**
|
||||
* \brief Get the next IPv6 header.
|
||||
* \param buffer A pointer to the buffer holding the IPv6 packet
|
||||
* \param size The size of the data in the buffer
|
||||
* \param protocol A pointer to a variable where the protocol of the header will be stored
|
||||
* \param start A flag that indicates if this is expected to be the IPv6 packet header or a later header (Extension header)
|
||||
* \retval returns address of the starting position of the next header
|
||||
*
|
||||
* This function moves to the next header in a IPv6 packet.
|
||||
*/
|
||||
uint8_t* uipbuf_get_next_header(uint8_t *buffer, uint16_t size, uint8_t *protocol, uint8_t start);
|
||||
/* Get the final header given the buffer - that is assumed to be at start
|
||||
of an IPv6 header */
|
||||
|
||||
|
||||
/**
|
||||
* \brief Get the last IPv6 header.
|
||||
* \param buffer A pointer to the buffer holding the IPv6 packet
|
||||
* \param size The size of the data in the buffer
|
||||
* \param protocol A pointer to a variable where the protocol of the header will be stored
|
||||
* \retval returns address of the starting position of the next header
|
||||
*
|
||||
* This function moves to the last header of the IPv6 packet.
|
||||
*/
|
||||
uint8_t* uipbuf_get_last_header(uint8_t *buffer, uint16_t size, uint8_t *protocol);
|
||||
|
||||
/* Attributes relating to the current packet in uipbuf */
|
||||
|
||||
/**
|
||||
* \brief Get the value of the attribute
|
||||
* \param type The attribute to get the value of
|
||||
* \retval the value of the attribute
|
||||
*
|
||||
* This function gets the value of a specific uipbuf attribute.
|
||||
*/
|
||||
uint16_t uipbuf_get_attr(uint8_t type);
|
||||
void uipbuf_set_attr_flag(uint16_t flag);
|
||||
void uipbuf_clr_attr_flag(uint16_t flag);
|
||||
uint16_t uipbuf_is_attr_flag(uint16_t flag);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Set the value of the attribute
|
||||
* \param type The attribute to set the value of
|
||||
* \param value The value to set
|
||||
* \retval 0 - indicates failure of setting the value
|
||||
* \retval 1 - indicates success of setting the value
|
||||
*
|
||||
* This function sets the value of a specific uipbuf attribute.
|
||||
*/
|
||||
int uipbuf_set_attr(uint8_t type, uint16_t value);
|
||||
|
||||
/**
|
||||
* \brief Set bits in the uipbuf attribute flags.
|
||||
* \param flag_bits The bits to set in the flag.
|
||||
*
|
||||
* This function sets the uipbuf attributes flag of specified bits.
|
||||
*/
|
||||
void uipbuf_set_attr_flag(uint16_t flag_bits);
|
||||
|
||||
/**
|
||||
* \brief Clear bits in the uipbuf attribute flags.
|
||||
* \param flag_bits The bits to clear in the flag.
|
||||
*
|
||||
* This function clears the uipbuf attributes flag of specified bits.
|
||||
*/
|
||||
void uipbuf_clr_attr_flag(uint16_t flag_bits);
|
||||
|
||||
/**
|
||||
* \brief Check if bits in the uipbuf attribute flag are set.
|
||||
* \param flag_bits The bits to check in the flag.
|
||||
*
|
||||
* This function checks if the specified bits are set in the
|
||||
* uipbuf attributes flag.
|
||||
*/
|
||||
uint16_t uipbuf_is_attr_flag(uint16_t flag_bits);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Clear all attributes.
|
||||
*
|
||||
* This function clear all attributes in the uipbuf attributes
|
||||
* including all flags.
|
||||
*/
|
||||
void uipbuf_clear_attr(void);
|
||||
|
||||
/* These flags will be used for being */
|
||||
/**
|
||||
* \brief The bits defined for uipbuf attributes flag.
|
||||
*
|
||||
*/
|
||||
/* Avoid using NHC compression on the packet (6LoWPAN) */
|
||||
#define UIPBUF_ATTR_FLAGS_6LOWPAN_NO_NHC_COMPRESSION 0x01
|
||||
/* Avoid using prefix compression on the packet (6LoWPAN) */
|
||||
#define UIPBUF_ATTR_FLAGS_6LOWPAN_NO_PREFIX_COMPRESSION 0x02
|
||||
|
||||
/**
|
||||
* \brief The attributes defined for uipbuf attributes function.
|
||||
*
|
||||
*/
|
||||
enum {
|
||||
UIPBUF_ATTR_LLSEC_LEVEL,
|
||||
UIPBUF_ATTR_LLSEC_KEY_ID,
|
||||
UIPBUF_ATTR_INTERFACE_ID,
|
||||
UIPBUF_ATTR_PHYSICAL_NETWORK_ID,
|
||||
UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS,
|
||||
UIPBUF_ATTR_FLAGS,
|
||||
UIPBUF_ATTR_LLSEC_LEVEL, /**< Control link layer security level. */
|
||||
UIPBUF_ATTR_LLSEC_KEY_ID, /**< Control link layer security key ID. */
|
||||
UIPBUF_ATTR_INTERFACE_ID, /**< The interface to output packet on */
|
||||
UIPBUF_ATTR_PHYSICAL_NETWORK_ID, /**< Physical network ID (mapped to PAN ID)*/
|
||||
UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS, /**< MAX transmissions of the packet MAC */
|
||||
UIPBUF_ATTR_FLAGS, /**< Flags that can control lower layers. see above. */
|
||||
UIPBUF_ATTR_MAX
|
||||
};
|
||||
|
||||
|
@ -370,6 +370,7 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
|
||||
}
|
||||
if(dag == dag->instance->current_dag) {
|
||||
PRINTF("RPL: Dropping a joined DAG when setting this node as root");
|
||||
rpl_set_default_route(instance, NULL);
|
||||
dag->instance->current_dag = NULL;
|
||||
} else {
|
||||
PRINTF("RPL: Dropping a DAG when setting this node as root");
|
||||
@ -522,14 +523,16 @@ rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, unsigned len)
|
||||
dag->prefix_info.length = len;
|
||||
dag->prefix_info.flags = UIP_ND6_RA_FLAG_AUTONOMOUS;
|
||||
PRINTF("RPL: Prefix set - will announce this in DIOs\n");
|
||||
/* Autoconfigure an address if this node does not already have an address
|
||||
with this prefix. Otherwise, update the prefix */
|
||||
if(last_len == 0) {
|
||||
PRINTF("rpl_set_prefix - prefix NULL\n");
|
||||
check_prefix(NULL, &dag->prefix_info);
|
||||
} else {
|
||||
PRINTF("rpl_set_prefix - prefix NON-NULL\n");
|
||||
check_prefix(&last_prefix, &dag->prefix_info);
|
||||
if(dag->rank != ROOT_RANK(dag->instance)) {
|
||||
/* Autoconfigure an address if this node does not already have an address
|
||||
with this prefix. Otherwise, update the prefix */
|
||||
if(last_len == 0) {
|
||||
PRINTF("rpl_set_prefix - prefix NULL\n");
|
||||
check_prefix(NULL, &dag->prefix_info);
|
||||
} else {
|
||||
PRINTF("rpl_set_prefix - prefix NON-NULL\n");
|
||||
check_prefix(&last_prefix, &dag->prefix_info);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -665,6 +668,10 @@ rpl_free_dag(rpl_dag_t *dag)
|
||||
if(RPL_IS_STORING(dag->instance)) {
|
||||
rpl_remove_routes(dag);
|
||||
}
|
||||
/* Stop the DAO retransmit timer */
|
||||
#if RPL_WITH_DAO_ACK
|
||||
ctimer_stop(&dag->instance->dao_retransmit_timer);
|
||||
#endif /* RPL_WITH_DAO_ACK */
|
||||
|
||||
/* Remove autoconfigured address */
|
||||
if((dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
|
||||
@ -757,22 +764,17 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
|
||||
old_rank = instance->current_dag->rank;
|
||||
last_parent = instance->current_dag->preferred_parent;
|
||||
|
||||
best_dag = instance->current_dag;
|
||||
if(best_dag->rank != ROOT_RANK(instance)) {
|
||||
if(rpl_select_parent(p->dag) != NULL) {
|
||||
if(p->dag != best_dag) {
|
||||
best_dag = instance->of->best_dag(best_dag, p->dag);
|
||||
}
|
||||
} else if(p->dag == best_dag) {
|
||||
best_dag = NULL;
|
||||
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
|
||||
if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != RPL_INFINITE_RANK) {
|
||||
if(best_dag == NULL) {
|
||||
best_dag = dag;
|
||||
} else {
|
||||
best_dag = instance->of->best_dag(best_dag, dag);
|
||||
}
|
||||
}
|
||||
if(instance->current_dag->rank != ROOT_RANK(instance)) {
|
||||
rpl_select_parent(p->dag);
|
||||
}
|
||||
|
||||
best_dag = NULL;
|
||||
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
|
||||
if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != RPL_INFINITE_RANK) {
|
||||
if(best_dag == NULL) {
|
||||
best_dag = dag;
|
||||
} else {
|
||||
best_dag = instance->of->best_dag(best_dag, dag);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1323,6 +1325,9 @@ rpl_local_repair(rpl_instance_t *instance)
|
||||
|
||||
/* no downward route anymore */
|
||||
instance->has_downward_route = 0;
|
||||
#if RPL_WITH_DAO_ACK
|
||||
ctimer_stop(&instance->dao_retransmit_timer);
|
||||
#endif /* RPL_WITH_DAO_ACK */
|
||||
|
||||
rpl_reset_dio_timer(instance);
|
||||
if(RPL_IS_STORING(instance)) {
|
||||
|
@ -408,7 +408,7 @@ insert_srh_header(void)
|
||||
path_len, cmpri, cmpre, ext_len, padding);
|
||||
|
||||
/* Check if there is enough space to store the extension header */
|
||||
if(uip_len + ext_len > UIP_BUFSIZE) {
|
||||
if(uip_len + ext_len > UIP_BUFSIZE - UIP_LLH_LEN) {
|
||||
PRINTF("RPL: Packet too long: impossible to add source routing header (%u bytes)\n", ext_len);
|
||||
return 0;
|
||||
}
|
||||
@ -553,7 +553,7 @@ insert_hbh_header(const rpl_instance_t *instance)
|
||||
|
||||
/* Insert hop-by-hop header */
|
||||
PRINTF("RPL: Creating hop-by-hop option\n");
|
||||
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
|
||||
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE - UIP_LLH_LEN) {
|
||||
PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
@ -592,9 +592,11 @@ rpl_ext_header_remove(void)
|
||||
{
|
||||
uint8_t temp_len;
|
||||
uint8_t rpl_ext_hdr_len;
|
||||
int uip_ext_opt_offset;
|
||||
uint8_t *uip_next_hdr;
|
||||
|
||||
uip_ext_len = 0;
|
||||
uip_ext_opt_offset = 2;
|
||||
uip_next_hdr = &UIP_IP_BUF->proto;
|
||||
|
||||
/* Look for hop-by-hop and routing headers */
|
||||
@ -602,17 +604,22 @@ rpl_ext_header_remove(void)
|
||||
switch(*uip_next_hdr) {
|
||||
case UIP_PROTO_HBHO:
|
||||
case UIP_PROTO_ROUTING:
|
||||
/* Remove hop-by-hop and routing headers */
|
||||
*uip_next_hdr = UIP_EXT_BUF->next;
|
||||
rpl_ext_hdr_len = (UIP_EXT_BUF->len * 8) + 8;
|
||||
temp_len = UIP_IP_BUF->len[1];
|
||||
uip_len -= rpl_ext_hdr_len;
|
||||
UIP_IP_BUF->len[1] -= rpl_ext_hdr_len;
|
||||
if(UIP_IP_BUF->len[1] > temp_len) {
|
||||
UIP_IP_BUF->len[0]--;
|
||||
if((*uip_next_hdr != UIP_PROTO_HBHO || UIP_EXT_HDR_OPT_RPL_BUF->opt_type == UIP_EXT_HDR_OPT_RPL)) {
|
||||
/* Remove hop-by-hop and routing headers */
|
||||
*uip_next_hdr = UIP_EXT_BUF->next;
|
||||
rpl_ext_hdr_len = (UIP_EXT_BUF->len * 8) + 8;
|
||||
temp_len = UIP_IP_BUF->len[1];
|
||||
uip_len -= rpl_ext_hdr_len;
|
||||
UIP_IP_BUF->len[1] -= rpl_ext_hdr_len;
|
||||
if(UIP_IP_BUF->len[1] > temp_len) {
|
||||
UIP_IP_BUF->len[0]--;
|
||||
}
|
||||
PRINTF("RPL: Removing RPL extension header (type %u, len %u)\n", *uip_next_hdr, rpl_ext_hdr_len);
|
||||
memmove(UIP_EXT_BUF, ((uint8_t *)UIP_EXT_BUF) + rpl_ext_hdr_len, uip_len - UIP_IPH_LEN);
|
||||
} else {
|
||||
uip_next_hdr = &UIP_EXT_BUF->next;
|
||||
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
|
||||
}
|
||||
PRINTF("RPL: Removing RPL extension header (type %u, len %u)\n", *uip_next_hdr, rpl_ext_hdr_len);
|
||||
memmove(UIP_EXT_BUF, ((uint8_t *)UIP_EXT_BUF) + rpl_ext_hdr_len, uip_len - UIP_IPH_LEN);
|
||||
break;
|
||||
case UIP_PROTO_DESTO:
|
||||
/*
|
||||
@ -626,6 +633,7 @@ rpl_ext_header_remove(void)
|
||||
/* Move to next header */
|
||||
uip_next_hdr = &UIP_EXT_BUF->next;
|
||||
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -1282,6 +1282,12 @@ dao_ack_input(void)
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
if(instance->current_dag->rank == ROOT_RANK(instance)) {
|
||||
PRINTF("RPL: DODAG root received a DAO ACK, ignoring it\n");
|
||||
uip_clear_buf();
|
||||
return;
|
||||
}
|
||||
|
||||
PRINTF("RPL: Received a DAO %s with sequence number %d (%d) and status %d from ",
|
||||
status < 128 ? "ACK" : "NACK",
|
||||
sequence, instance->my_dao_seqno, status);
|
||||
|
@ -56,6 +56,7 @@
|
||||
typedef struct rpl_ns_node {
|
||||
struct rpl_ns_node *next;
|
||||
uint32_t lifetime;
|
||||
rpl_dag_t *dag;
|
||||
/* Store only IPv6 link identifiers as all nodes in the DAG share the same prefix */
|
||||
unsigned char link_identifier[8];
|
||||
struct rpl_ns_node *parent;
|
||||
|
@ -199,13 +199,6 @@
|
||||
#define RPL_ROUTE_FROM_MULTICAST_DAO 2
|
||||
#define RPL_ROUTE_FROM_DIO 3
|
||||
|
||||
/* Multicast Route Lifetime as a multiple of the lifetime unit */
|
||||
#ifdef RPL_CONF_MCAST_LIFETIME
|
||||
#define RPL_MCAST_LIFETIME RPL_CONF_MCAST_LIFETIME
|
||||
#else
|
||||
#define RPL_MCAST_LIFETIME 3
|
||||
#endif
|
||||
|
||||
/* DIS related */
|
||||
#define RPL_DIS_SEND 1
|
||||
|
||||
|
@ -283,7 +283,7 @@ handle_dao_timer(void *ptr)
|
||||
if(uip_ds6_if.maddr_list[i].isused
|
||||
&& uip_is_addr_mcast_global(&uip_ds6_if.maddr_list[i].ipaddr)) {
|
||||
dao_output_target(instance->current_dag->preferred_parent,
|
||||
&uip_ds6_if.maddr_list[i].ipaddr, RPL_MCAST_LIFETIME);
|
||||
&uip_ds6_if.maddr_list[i].ipaddr, instance->default_lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,7 +293,7 @@ handle_dao_timer(void *ptr)
|
||||
/* Don't send if it's also our own address, done that already */
|
||||
if(uip_ds6_maddr_lookup(&mcast_route->group) == NULL) {
|
||||
dao_output_target(instance->current_dag->preferred_parent,
|
||||
&mcast_route->group, RPL_MCAST_LIFETIME);
|
||||
&mcast_route->group, instance->default_lifetime);
|
||||
}
|
||||
mcast_route = list_item_next(mcast_route);
|
||||
}
|
||||
@ -457,11 +457,29 @@ get_probing_target(rpl_dag_t *dag)
|
||||
return probing_target;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static rpl_dag_t *
|
||||
get_next_dag(rpl_instance_t *instance)
|
||||
{
|
||||
rpl_dag_t *dag = NULL;
|
||||
int new_dag = instance->last_dag;
|
||||
do {
|
||||
new_dag++;
|
||||
if(new_dag >= RPL_MAX_DAG_PER_INSTANCE) {
|
||||
new_dag = 0;
|
||||
}
|
||||
if(instance->dag_table[new_dag].used) {
|
||||
dag = &instance->dag_table[new_dag];
|
||||
}
|
||||
} while(new_dag != instance->last_dag && dag == NULL);
|
||||
instance->last_dag = new_dag;
|
||||
return dag;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
handle_probing_timer(void *ptr)
|
||||
{
|
||||
rpl_instance_t *instance = (rpl_instance_t *)ptr;
|
||||
rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(instance->current_dag);
|
||||
rpl_parent_t *probing_target = RPL_PROBING_SELECT_FUNC(get_next_dag(instance));
|
||||
uip_ipaddr_t *target_ipaddr = rpl_parent_get_ipaddr(probing_target);
|
||||
|
||||
/* Perform probing */
|
||||
|
@ -252,6 +252,7 @@ struct rpl_instance {
|
||||
#if RPL_WITH_PROBING
|
||||
struct ctimer probing_timer;
|
||||
rpl_parent_t *urgent_probing_target;
|
||||
int last_dag;
|
||||
#endif /* RPL_WITH_PROBING */
|
||||
struct ctimer dio_timer;
|
||||
struct ctimer dao_timer;
|
||||
|
@ -302,7 +302,7 @@ insert_srh_header(void)
|
||||
path_len, cmpri, cmpre, ext_len, padding);
|
||||
|
||||
/* Check if there is enough space to store the extension header */
|
||||
if(uip_len + ext_len > UIP_BUFSIZE) {
|
||||
if(uip_len + ext_len > UIP_BUFSIZE - UIP_LLH_LEN) {
|
||||
LOG_ERR("packet too long: impossible to add source routing header (%u bytes)\n", ext_len);
|
||||
return 0;
|
||||
}
|
||||
@ -464,7 +464,7 @@ insert_hbh_header(void)
|
||||
|
||||
/* Insert hop-by-hop header */
|
||||
LOG_INFO("creating hop-by-hop option\n");
|
||||
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
|
||||
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE - UIP_LLH_LEN) {
|
||||
LOG_ERR("packet too long: impossible to add hop-by-hop option\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
@ -531,9 +531,11 @@ rpl_ext_header_remove(void)
|
||||
{
|
||||
uint8_t temp_len;
|
||||
uint8_t rpl_ext_hdr_len;
|
||||
int uip_ext_opt_offset;
|
||||
uint8_t *uip_next_hdr;
|
||||
|
||||
uip_ext_len = 0;
|
||||
uip_ext_opt_offset = 2;
|
||||
uip_next_hdr = &UIP_IP_BUF->proto;
|
||||
|
||||
/* Look for hop-by-hop and routing headers */
|
||||
@ -541,17 +543,22 @@ rpl_ext_header_remove(void)
|
||||
switch(*uip_next_hdr) {
|
||||
case UIP_PROTO_HBHO:
|
||||
case UIP_PROTO_ROUTING:
|
||||
/* Remove hop-by-hop and routing headers */
|
||||
*uip_next_hdr = UIP_EXT_BUF->next;
|
||||
rpl_ext_hdr_len = (UIP_EXT_BUF->len * 8) + 8;
|
||||
temp_len = UIP_IP_BUF->len[1];
|
||||
uip_len -= rpl_ext_hdr_len;
|
||||
UIP_IP_BUF->len[1] -= rpl_ext_hdr_len;
|
||||
if(UIP_IP_BUF->len[1] > temp_len) {
|
||||
UIP_IP_BUF->len[0]--;
|
||||
if((*uip_next_hdr != UIP_PROTO_HBHO || UIP_EXT_HDR_OPT_RPL_BUF->opt_type == UIP_EXT_HDR_OPT_RPL)) {
|
||||
/* Remove hop-by-hop and routing headers */
|
||||
*uip_next_hdr = UIP_EXT_BUF->next;
|
||||
rpl_ext_hdr_len = (UIP_EXT_BUF->len * 8) + 8;
|
||||
temp_len = UIP_IP_BUF->len[1];
|
||||
uip_len -= rpl_ext_hdr_len;
|
||||
UIP_IP_BUF->len[1] -= rpl_ext_hdr_len;
|
||||
if(UIP_IP_BUF->len[1] > temp_len) {
|
||||
UIP_IP_BUF->len[0]--;
|
||||
}
|
||||
LOG_INFO("removing RPL extension header (type %u, len %u)\n", *uip_next_hdr, rpl_ext_hdr_len);
|
||||
memmove(UIP_EXT_BUF, ((uint8_t *)UIP_EXT_BUF) + rpl_ext_hdr_len, uip_len - UIP_IPH_LEN);
|
||||
} else {
|
||||
uip_next_hdr = &UIP_EXT_BUF->next;
|
||||
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
|
||||
}
|
||||
LOG_INFO("removing RPL extension header (type %u, len %u)\n", *uip_next_hdr, rpl_ext_hdr_len);
|
||||
memmove(UIP_EXT_BUF, ((uint8_t *)UIP_EXT_BUF) + rpl_ext_hdr_len, uip_len - UIP_IPH_LEN);
|
||||
break;
|
||||
case UIP_PROTO_DESTO:
|
||||
/*
|
||||
@ -565,6 +572,7 @@ rpl_ext_header_remove(void)
|
||||
/* Move to next header */
|
||||
uip_next_hdr = &UIP_EXT_BUF->next;
|
||||
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ struct dhcp_msg {
|
||||
uint8_t options[312];
|
||||
};
|
||||
|
||||
#if (UIP_BUFSIZE - UIP_UDPIP_HLEN) < 548
|
||||
#if (UIP_BUFSIZE - UIP_LLH_LEN - UIP_UDPIP_HLEN) < 548
|
||||
#error UIP_CONF_BUFFER_SIZE may be too small to accomodate DHCPv4 packets
|
||||
#error Increase UIP_CONF_BUFFER_SIZE in your project-conf.h, or contiki-conf.h
|
||||
#error A good size is 600 bytes
|
||||
|
@ -30,15 +30,15 @@ DOCDIR=../../tools/doxygen
|
||||
all: clean summary
|
||||
|
||||
doxygen:
|
||||
@make -C $(DOCDIR) 2> doxygen.runerr > doxygen.runlog
|
||||
@make -C $(DOCDIR) 2> doxygen.err > /dev/null
|
||||
|
||||
summary: doxygen
|
||||
@( \
|
||||
1> summary; \
|
||||
if [ -s doxygen.runerr ] ; then \
|
||||
if [ -s doxygen.err ] ; then \
|
||||
echo "Doxygen: TEST FAIL" | tee summary; \
|
||||
echo "Errors:"; \
|
||||
cat doxygen.runerr; \
|
||||
cat doxygen.err; \
|
||||
fi ; \
|
||||
if [ -s $(DOCDIR)/doxygen.log ] ; then \
|
||||
echo "Doxygen: TEST FAIL" | tee summary; \
|
||||
@ -49,10 +49,10 @@ summary: doxygen
|
||||
echo "Doxygen: TEST OK (no warning nor error)" | tee summary; \
|
||||
fi ; \
|
||||
)
|
||||
@rm doxygen.runlog doxygen.runerr
|
||||
@rm doxygen.err
|
||||
@echo "========== Summary =========="
|
||||
@cat summary
|
||||
|
||||
clean:
|
||||
@rm -f summary doxygen.runlog doxygen.runerr
|
||||
@rm -f summary doxygen.err
|
||||
@make -C $(DOCDIR) clean
|
||||
|
@ -3,16 +3,20 @@ TOOLSDIR=../../tools
|
||||
|
||||
EXAMPLES = \
|
||||
hello-world/native \
|
||||
hello-world/native:MAKE_NET=MAKE_NET_NULLNET \
|
||||
hello-world/sky \
|
||||
storage/eeprom-test/native \
|
||||
multicast/sky \
|
||||
libs/logging/native \
|
||||
libs/energest/native \
|
||||
libs/energest/sky \
|
||||
libs/data-structures/native \
|
||||
libs/data-structures/sky \
|
||||
rpl-udp/sky \
|
||||
rpl-border-router/native \
|
||||
rpl-border-router/sky \
|
||||
slip-radio/sky \
|
||||
nullnet/native \
|
||||
|
||||
TOOLS=
|
||||
|
||||
|
@ -34,6 +34,7 @@ platform-specific/nrf52dk/coap-demo/nrf52dk:coap-client:SERVER_IPV6_ADDR=ffff \
|
||||
platform-specific/nrf52dk/mqtt-demo/nrf52dk \
|
||||
platform-specific/nrf52dk/blink-hello/nrf52dk \
|
||||
platform-specific/nrf52dk/timer-test/nrf52dk \
|
||||
libs/data-structures/nrf52dk \
|
||||
libs/logging/nrf52dk
|
||||
|
||||
TOOLS=
|
||||
|
@ -26,6 +26,7 @@ http-socket/zoul \
|
||||
libs/timers/zoul \
|
||||
libs/energest/zoul \
|
||||
libs/trickle-library/zoul \
|
||||
libs/data-structures/zoul \
|
||||
nullnet/zoul \
|
||||
slip-radio/zoul \
|
||||
storage/cfs-coffee/openmote-cc2538 \
|
||||
|
98
tests/07-simulation-base/31-data-structures-sky.csc
Normal file
98
tests/07-simulation-base/31-data-structures-sky.csc
Normal file
@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<simconf>
|
||||
<project EXPORT="discard">[APPS_DIR]/mrm</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/avrora</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
|
||||
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
|
||||
<simulation>
|
||||
<title>data-structures-sky</title>
|
||||
<randomseed>123456</randomseed>
|
||||
<motedelay_us>1000000</motedelay_us>
|
||||
<radiomedium>
|
||||
org.contikios.cooja.radiomediums.UDGM
|
||||
<transmitting_range>50.0</transmitting_range>
|
||||
<interference_range>100.0</interference_range>
|
||||
<success_ratio_tx>1.0</success_ratio_tx>
|
||||
<success_ratio_rx>1.0</success_ratio_rx>
|
||||
</radiomedium>
|
||||
<events>
|
||||
<logoutput>40000</logoutput>
|
||||
</events>
|
||||
<motetype>
|
||||
org.contikios.cooja.mspmote.SkyMoteType
|
||||
<identifier>sky1</identifier>
|
||||
<description>Sky Mote Type #sky1</description>
|
||||
<source EXPORT="discard">[CONTIKI_DIR]/tests/07-simulation-base/code-data-structures/test-data-structures.c</source>
|
||||
<commands EXPORT="discard">make test-data-structures.sky TARGET=sky</commands>
|
||||
<firmware EXPORT="copy">[CONTIKI_DIR]/tests/07-simulation-base/code-data-structures/test-data-structures.sky</firmware>
|
||||
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyButton</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyFlash</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspSerial</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyLED</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
|
||||
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyTemperature</moteinterface>
|
||||
</motetype>
|
||||
<mote>
|
||||
<breakpoints />
|
||||
<interface_config>
|
||||
org.contikios.cooja.interfaces.Position
|
||||
<x>3.086692968239446</x>
|
||||
<y>5.726233183606267</y>
|
||||
<z>0.0</z>
|
||||
</interface_config>
|
||||
<interface_config>
|
||||
org.contikios.cooja.mspmote.interfaces.MspClock
|
||||
<deviation>1.0</deviation>
|
||||
</interface_config>
|
||||
<interface_config>
|
||||
org.contikios.cooja.mspmote.interfaces.MspMoteID
|
||||
<id>1</id>
|
||||
</interface_config>
|
||||
<motetype_identifier>sky1</motetype_identifier>
|
||||
</mote>
|
||||
</simulation>
|
||||
<plugin>
|
||||
org.contikios.cooja.plugins.SimControl
|
||||
<width>280</width>
|
||||
<z>2</z>
|
||||
<height>160</height>
|
||||
<location_x>400</location_x>
|
||||
<location_y>0</location_y>
|
||||
</plugin>
|
||||
<plugin>
|
||||
org.contikios.cooja.plugins.LogListener
|
||||
<plugin_config>
|
||||
<filter />
|
||||
<formatted_time />
|
||||
<coloring />
|
||||
</plugin_config>
|
||||
<width>586</width>
|
||||
<z>1</z>
|
||||
<height>666</height>
|
||||
<location_x>400</location_x>
|
||||
<location_y>160</location_y>
|
||||
</plugin>
|
||||
<plugin>
|
||||
org.contikios.cooja.plugins.ScriptRunner
|
||||
<plugin_config>
|
||||
<scriptfile>[CONFIG_DIR]/js/data-structures.js</scriptfile>
|
||||
<active>true</active>
|
||||
</plugin_config>
|
||||
<width>600</width>
|
||||
<z>0</z>
|
||||
<height>700</height>
|
||||
<location_x>5</location_x>
|
||||
<location_y>1</location_y>
|
||||
</plugin>
|
||||
</simconf>
|
9
tests/07-simulation-base/code-data-structures/Makefile
Normal file
9
tests/07-simulation-base/code-data-structures/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
all: test-data-structures
|
||||
|
||||
MODULES += os/services/unit-test
|
||||
|
||||
MAKE_MAC = MAKE_MAC_NULLMAC
|
||||
MAKE_NET = MAKE_NET_NULLNET
|
||||
|
||||
CONTIKI = ../../..
|
||||
include $(CONTIKI)/Makefile.include
|
37
tests/07-simulation-base/code-data-structures/project-conf.h
Normal file
37
tests/07-simulation-base/code-data-structures/project-conf.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Yasuyuki Tanaka
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PROJECT_CONF_H_
|
||||
#define PROJECT_CONF_H_
|
||||
|
||||
#define UNIT_TEST_PRINT_FUNCTION print_test_report
|
||||
|
||||
#endif /* PROJECT_CONF_H_ */
|
@ -0,0 +1,897 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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 "lib/stack.h"
|
||||
#include "lib/queue.h"
|
||||
#include "lib/circular-list.h"
|
||||
#include "lib/dbl-list.h"
|
||||
#include "lib/dbl-circ-list.h"
|
||||
#include "lib/random.h"
|
||||
#include "services/unit-test/unit-test.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(data_structure_test_process, "Data structure process");
|
||||
AUTOSTART_PROCESSES(&data_structure_test_process);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
typedef struct demo_struct_s {
|
||||
struct demo_struct_s *next;
|
||||
struct demo_struct_s *previous;
|
||||
} demo_struct_t;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define ELEMENT_COUNT 10
|
||||
static demo_struct_t elements[ELEMENT_COUNT];
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
print_test_report(const unit_test_t *utp)
|
||||
{
|
||||
printf("=check-me= ");
|
||||
if(utp->result == unit_test_failure) {
|
||||
printf("FAILED - %s: exit at L%u\n", utp->descr, utp->exit_line);
|
||||
} else {
|
||||
printf("SUCCEEDED - %s\n", utp->descr);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
UNIT_TEST_REGISTER(test_stack, "Stack Push/Pop");
|
||||
UNIT_TEST(test_stack)
|
||||
{
|
||||
STACK(stack);
|
||||
|
||||
UNIT_TEST_BEGIN();
|
||||
|
||||
memset(elements, 0, sizeof(elements));
|
||||
stack_init(stack);
|
||||
|
||||
/* Starts from empty */
|
||||
UNIT_TEST_ASSERT(stack_is_empty(stack) == true);
|
||||
UNIT_TEST_ASSERT(stack_peek(stack) == NULL);
|
||||
UNIT_TEST_ASSERT(stack_pop(stack) == NULL);
|
||||
|
||||
/*
|
||||
* Push two elements. Peek and pop should be the last one. Stack should be
|
||||
* non-empty after the pop
|
||||
*/
|
||||
stack_push(stack, &elements[0]);
|
||||
stack_push(stack, &elements[1]);
|
||||
|
||||
UNIT_TEST_ASSERT(stack_peek(stack) == &elements[1]);
|
||||
UNIT_TEST_ASSERT(stack_pop(stack) == &elements[1]);
|
||||
UNIT_TEST_ASSERT(stack_peek(stack) == &elements[0]);
|
||||
UNIT_TEST_ASSERT(stack_is_empty(stack) == false);
|
||||
UNIT_TEST_ASSERT(stack_pop(stack) == &elements[0]);
|
||||
|
||||
/* Ends empty */
|
||||
UNIT_TEST_ASSERT(stack_is_empty(stack) == true);
|
||||
UNIT_TEST_ASSERT(stack_peek(stack) == NULL);
|
||||
UNIT_TEST_ASSERT(stack_pop(stack) == NULL);
|
||||
|
||||
UNIT_TEST_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
UNIT_TEST_REGISTER(test_queue, "Queue Enqueue/Dequeue");
|
||||
UNIT_TEST(test_queue)
|
||||
{
|
||||
QUEUE(queue);
|
||||
|
||||
UNIT_TEST_BEGIN();
|
||||
|
||||
memset(elements, 0, sizeof(elements));
|
||||
queue_init(queue);
|
||||
|
||||
/* Starts from empty */
|
||||
UNIT_TEST_ASSERT(queue_is_empty(queue) == true);
|
||||
UNIT_TEST_ASSERT(queue_peek(queue) == NULL);
|
||||
UNIT_TEST_ASSERT(queue_dequeue(queue) == NULL);
|
||||
|
||||
/* Enqueue three elements. They should come out in the same order */
|
||||
queue_enqueue(queue, &elements[0]);
|
||||
queue_enqueue(queue, &elements[1]);
|
||||
queue_enqueue(queue, &elements[2]);
|
||||
|
||||
UNIT_TEST_ASSERT(queue_dequeue(queue) == &elements[0]);
|
||||
UNIT_TEST_ASSERT(queue_dequeue(queue) == &elements[1]);
|
||||
UNIT_TEST_ASSERT(queue_dequeue(queue) == &elements[2]);
|
||||
|
||||
/* Should be empty */
|
||||
UNIT_TEST_ASSERT(queue_is_empty(queue) == true);
|
||||
UNIT_TEST_ASSERT(queue_peek(queue) == NULL);
|
||||
UNIT_TEST_ASSERT(queue_dequeue(queue) == NULL);
|
||||
|
||||
UNIT_TEST_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
UNIT_TEST_REGISTER(test_csll, "Circular, singly-linked list");
|
||||
UNIT_TEST(test_csll)
|
||||
{
|
||||
demo_struct_t *head, *tail;
|
||||
|
||||
CIRCULAR_LIST(csll);
|
||||
|
||||
UNIT_TEST_BEGIN();
|
||||
|
||||
memset(elements, 0, sizeof(elements));
|
||||
circular_list_init(csll);
|
||||
|
||||
/* Starts from empty */
|
||||
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == true);
|
||||
UNIT_TEST_ASSERT(circular_list_length(csll) == 0);
|
||||
UNIT_TEST_ASSERT(circular_list_head(csll) == NULL);
|
||||
UNIT_TEST_ASSERT(circular_list_tail(csll) == NULL);
|
||||
|
||||
/* Add one element. Should point to itself and act as head and tail */
|
||||
circular_list_add(csll, &elements[0]);
|
||||
|
||||
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == false);
|
||||
UNIT_TEST_ASSERT(circular_list_length(csll) == 1);
|
||||
UNIT_TEST_ASSERT(circular_list_head(csll) == &elements[0]);
|
||||
UNIT_TEST_ASSERT(circular_list_tail(csll) == &elements[0]);
|
||||
UNIT_TEST_ASSERT(elements[0].next == &elements[0]);
|
||||
|
||||
/* Add a second element. The two should point to each-other */
|
||||
circular_list_add(csll, &elements[1]);
|
||||
UNIT_TEST_ASSERT(elements[0].next == &elements[1]);
|
||||
UNIT_TEST_ASSERT(elements[1].next == &elements[0]);
|
||||
|
||||
/*
|
||||
* Add a third element and check that head->next->next points to tail.
|
||||
* Check that tail->next points to the head
|
||||
*/
|
||||
circular_list_add(csll, &elements[2]);
|
||||
head = circular_list_head(csll);
|
||||
tail = circular_list_tail(csll);
|
||||
|
||||
UNIT_TEST_ASSERT(head->next->next == circular_list_tail(csll));
|
||||
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
|
||||
|
||||
/* Re-add an existing element. Check the list's integrity */
|
||||
circular_list_add(csll, &elements[1]);
|
||||
head = circular_list_head(csll);
|
||||
tail = circular_list_tail(csll);
|
||||
|
||||
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == false);
|
||||
UNIT_TEST_ASSERT(circular_list_length(csll) == 3);
|
||||
UNIT_TEST_ASSERT(head->next->next->next == circular_list_head(csll));
|
||||
UNIT_TEST_ASSERT(head->next->next == circular_list_tail(csll));
|
||||
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
|
||||
|
||||
/* Add another two elements, then start testing removal */
|
||||
circular_list_add(csll, &elements[3]);
|
||||
circular_list_add(csll, &elements[4]);
|
||||
|
||||
/* Remove an item in the middle and test list integrity */
|
||||
head = circular_list_head(csll);
|
||||
circular_list_remove(csll, head->next->next);
|
||||
head = circular_list_head(csll);
|
||||
tail = circular_list_tail(csll);
|
||||
|
||||
UNIT_TEST_ASSERT(circular_list_length(csll) == 4);
|
||||
UNIT_TEST_ASSERT(head->next->next->next->next == circular_list_head(csll));
|
||||
UNIT_TEST_ASSERT(head->next->next->next == circular_list_tail(csll));
|
||||
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
|
||||
|
||||
/* Remove the head and test list integrity */
|
||||
circular_list_remove(csll, circular_list_head(csll));
|
||||
head = circular_list_head(csll);
|
||||
tail = circular_list_tail(csll);
|
||||
|
||||
UNIT_TEST_ASSERT(circular_list_length(csll) == 3);
|
||||
UNIT_TEST_ASSERT(head->next->next->next == circular_list_head(csll));
|
||||
UNIT_TEST_ASSERT(head->next->next == circular_list_tail(csll));
|
||||
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
|
||||
|
||||
/* Remove the tail and test list integrity */
|
||||
circular_list_remove(csll, circular_list_tail(csll));
|
||||
head = circular_list_head(csll);
|
||||
tail = circular_list_tail(csll);
|
||||
|
||||
UNIT_TEST_ASSERT(circular_list_length(csll) == 2);
|
||||
UNIT_TEST_ASSERT(head->next->next == circular_list_head(csll));
|
||||
UNIT_TEST_ASSERT(head->next == circular_list_tail(csll));
|
||||
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
|
||||
|
||||
/*
|
||||
* Remove the tail
|
||||
* Only one item left: Make sure the head and tail are the same and point to
|
||||
* each other
|
||||
*/
|
||||
circular_list_remove(csll, circular_list_tail(csll));
|
||||
head = circular_list_head(csll);
|
||||
tail = circular_list_tail(csll);
|
||||
|
||||
UNIT_TEST_ASSERT(circular_list_length(csll) == 1);
|
||||
UNIT_TEST_ASSERT(head == tail);
|
||||
UNIT_TEST_ASSERT(head->next->next == circular_list_head(csll));
|
||||
UNIT_TEST_ASSERT(head->next == circular_list_head(csll));
|
||||
UNIT_TEST_ASSERT(head->next == circular_list_tail(csll));
|
||||
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
|
||||
UNIT_TEST_ASSERT(tail->next == circular_list_tail(csll));
|
||||
|
||||
/* Remove the last element by removing the head */
|
||||
circular_list_remove(csll, circular_list_head(csll));
|
||||
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == true);
|
||||
UNIT_TEST_ASSERT(circular_list_length(csll) == 0);
|
||||
UNIT_TEST_ASSERT(circular_list_head(csll) == NULL);
|
||||
UNIT_TEST_ASSERT(circular_list_tail(csll) == NULL);
|
||||
|
||||
/* Remove the last element by removing the tail */
|
||||
circular_list_add(csll, &elements[0]);
|
||||
circular_list_remove(csll, circular_list_tail(csll));
|
||||
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == true);
|
||||
UNIT_TEST_ASSERT(circular_list_length(csll) == 0);
|
||||
UNIT_TEST_ASSERT(circular_list_head(csll) == NULL);
|
||||
UNIT_TEST_ASSERT(circular_list_tail(csll) == NULL);
|
||||
|
||||
UNIT_TEST_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
UNIT_TEST_REGISTER(test_dll, "Doubly-linked list");
|
||||
UNIT_TEST(test_dll)
|
||||
{
|
||||
demo_struct_t *head, *tail;
|
||||
|
||||
CIRCULAR_LIST(dll);
|
||||
|
||||
UNIT_TEST_BEGIN();
|
||||
|
||||
memset(elements, 0, sizeof(elements));
|
||||
|
||||
/* Starts from empty */
|
||||
dbl_list_init(dll);
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == true);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 0);
|
||||
UNIT_TEST_ASSERT(dbl_list_head(dll) == NULL);
|
||||
UNIT_TEST_ASSERT(dbl_list_tail(dll) == NULL);
|
||||
|
||||
/*
|
||||
* Add an item by adding to the head.
|
||||
* Head and tail should point to NULL in both directions
|
||||
*/
|
||||
dbl_list_add_head(dll, &elements[0]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 1);
|
||||
UNIT_TEST_ASSERT(head == &elements[0]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[0]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == NULL);
|
||||
UNIT_TEST_ASSERT(tail->previous == NULL);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Add an item by adding to the tail.
|
||||
* Head and tail should point to NULL in both directions
|
||||
*/
|
||||
dbl_list_remove(dll, dbl_list_head(dll));
|
||||
dbl_list_add_tail(dll, &elements[1]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 1);
|
||||
UNIT_TEST_ASSERT(head == &elements[1]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == NULL);
|
||||
UNIT_TEST_ASSERT(tail->previous == NULL);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Add a second item to head. Head points forward to tail.
|
||||
* Tail points backwards to head.
|
||||
*/
|
||||
dbl_list_add_head(dll, &elements[2]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 2);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == tail);
|
||||
UNIT_TEST_ASSERT(tail->previous == head);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Add before head.
|
||||
* NULL <-- 3 --> 2 --> 1 --> NULL
|
||||
*/
|
||||
dbl_list_add_before(dll, dbl_list_head(dll), &elements[3]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 3);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == &elements[2]);
|
||||
UNIT_TEST_ASSERT(head->next->next == tail);
|
||||
UNIT_TEST_ASSERT(head->next->next->next == NULL);
|
||||
UNIT_TEST_ASSERT(tail->previous == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail->previous->previous == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail->previous->previous->previous == NULL);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Add after head.
|
||||
* NULL <-- 3 --> 4 --> 2 --> 1 --> NULL
|
||||
*/
|
||||
dbl_list_add_after(dll, dbl_list_head(dll), &elements[4]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 4);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == &elements[4]);
|
||||
UNIT_TEST_ASSERT(head->next->next == &elements[2]);
|
||||
UNIT_TEST_ASSERT(head->next->next->next == tail);
|
||||
UNIT_TEST_ASSERT(head->next->next->next->next == NULL);
|
||||
UNIT_TEST_ASSERT(tail->previous == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail->previous->previous == &elements[4]);
|
||||
UNIT_TEST_ASSERT(tail->previous->previous->previous == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail->previous->previous->previous->previous == NULL);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Add at 3rd position by adding after 2nd
|
||||
* NULL <-- 3 --> 4 --> 5 --> 2 --> 1 --> NULL
|
||||
*/
|
||||
dbl_list_add_after(dll, &elements[4], &elements[5]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 5);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == &elements[4]);
|
||||
UNIT_TEST_ASSERT(head->next->next == &elements[5]);
|
||||
UNIT_TEST_ASSERT(tail->previous->previous == &elements[5]);
|
||||
UNIT_TEST_ASSERT(tail->previous == &elements[2]);
|
||||
UNIT_TEST_ASSERT(elements[5].next == &elements[2]);
|
||||
UNIT_TEST_ASSERT(elements[5].previous == &elements[4]);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Add at 3rd position by adding before 3rd
|
||||
* NULL <-- 3 --> 4 --> 6 --> 5 --> 2 --> 1 --> NULL
|
||||
*/
|
||||
dbl_list_add_before(dll, &elements[5], &elements[6]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 6);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == &elements[4]);
|
||||
UNIT_TEST_ASSERT(head->next->next == &elements[6]);
|
||||
UNIT_TEST_ASSERT(tail->previous->previous == &elements[5]);
|
||||
UNIT_TEST_ASSERT(elements[6].next == &elements[5]);
|
||||
UNIT_TEST_ASSERT(elements[6].previous == &elements[4]);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Add before tail
|
||||
* NULL <-- 3 --> 4 --> 6 --> 5 --> 2 --> 7 --> 1 --> NULL
|
||||
*/
|
||||
dbl_list_add_before(dll, dbl_list_tail(dll), &elements[7]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 7);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(tail->previous == &elements[7]);
|
||||
UNIT_TEST_ASSERT(elements[7].next == &elements[1]);
|
||||
UNIT_TEST_ASSERT(elements[7].previous == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Add after tail
|
||||
* NULL <-- 3 --> 4 --> 6 --> 5 --> 2 --> 7 --> 1 --> 8 --> NULL
|
||||
*/
|
||||
dbl_list_add_after(dll, dbl_list_tail(dll), &elements[8]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 8);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[8]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(tail->previous == &elements[1]);
|
||||
UNIT_TEST_ASSERT(elements[8].next == NULL);
|
||||
UNIT_TEST_ASSERT(elements[8].previous == &elements[1]);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Find and remove element 5
|
||||
* NULL <-- 3 --> 4 --> 6 --> 2 --> 7 --> 1 --> 8 --> NULL
|
||||
*/
|
||||
dbl_list_remove(dll, &elements[5]);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 7);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[8]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(elements[6].next == &elements[2]);
|
||||
UNIT_TEST_ASSERT(elements[2].previous == &elements[6]);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Remove before tail
|
||||
* NULL <-- 3 --> 4 --> 6 --> 2 --> 7 --> 8 --> NULL
|
||||
*/
|
||||
dbl_list_remove(dll, ((demo_struct_t *)dbl_list_tail(dll))->previous);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 6);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[8]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(elements[7].next == tail);
|
||||
UNIT_TEST_ASSERT(tail->previous == &elements[7]);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Remove after head
|
||||
* NULL <-- 3 --> 6 --> 2 --> 7 --> 8 --> NULL
|
||||
*/
|
||||
dbl_list_remove(dll, ((demo_struct_t *)dbl_list_head(dll))->next);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 5);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[8]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == &elements[6]);
|
||||
UNIT_TEST_ASSERT(elements[6].previous == head);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Find element 2 and remove whatever is after it
|
||||
* NULL <-- 3 --> 6 --> 2 --> 8 --> NULL
|
||||
*/
|
||||
dbl_list_remove(dll, elements[2].next);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 4);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[8]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(elements[2].next == tail);
|
||||
UNIT_TEST_ASSERT(tail->previous == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Find element 2 and remove whatever is before it
|
||||
* NULL <-- 3 --> 2 --> 8 --> NULL
|
||||
*/
|
||||
dbl_list_remove(dll, elements[2].previous);
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 3);
|
||||
UNIT_TEST_ASSERT(head == &elements[3]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[8]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == &elements[2]);
|
||||
UNIT_TEST_ASSERT(elements[2].previous == head);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Remove head
|
||||
* NULL <-- 2 --> 8 --> NULL
|
||||
*/
|
||||
dbl_list_remove(dll, dbl_list_head(dll));
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 2);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[8]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == tail);
|
||||
UNIT_TEST_ASSERT(tail->previous == head);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/*
|
||||
* Remove tail
|
||||
* NULL <-- 8 --> NULL
|
||||
*/
|
||||
dbl_list_remove(dll, dbl_list_head(dll));
|
||||
head = dbl_list_head(dll);
|
||||
tail = dbl_list_tail(dll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 1);
|
||||
UNIT_TEST_ASSERT(head == &elements[8]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[8]);
|
||||
UNIT_TEST_ASSERT(head->previous == NULL);
|
||||
UNIT_TEST_ASSERT(head->next == NULL);
|
||||
UNIT_TEST_ASSERT(tail->previous == NULL);
|
||||
UNIT_TEST_ASSERT(tail->next == NULL);
|
||||
|
||||
/* Remove the last element */
|
||||
dbl_list_remove(dll, dbl_list_head(dll));
|
||||
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == true);
|
||||
UNIT_TEST_ASSERT(dbl_list_length(dll) == 0);
|
||||
UNIT_TEST_ASSERT(dbl_list_head(dll) == NULL);
|
||||
UNIT_TEST_ASSERT(dbl_list_tail(dll) == NULL);
|
||||
|
||||
UNIT_TEST_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
UNIT_TEST_REGISTER(test_cdll, "Circular, doubly-linked list");
|
||||
UNIT_TEST(test_cdll)
|
||||
{
|
||||
demo_struct_t *head, *tail;
|
||||
|
||||
CIRCULAR_LIST(cdll);
|
||||
|
||||
UNIT_TEST_BEGIN();
|
||||
|
||||
memset(elements, 0, sizeof(elements));
|
||||
|
||||
/* Starts from empty */
|
||||
dbl_circ_list_init(cdll);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == true);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 0);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_head(cdll) == NULL);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_tail(cdll) == NULL);
|
||||
|
||||
/*
|
||||
* Add an item by adding to the head.
|
||||
* Head and tail should be the same element and should point to itself in
|
||||
* both directions
|
||||
*/
|
||||
dbl_circ_list_add_head(cdll, &elements[0]);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 1);
|
||||
UNIT_TEST_ASSERT(head == &elements[0]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[0]);
|
||||
UNIT_TEST_ASSERT(head->previous == head);
|
||||
UNIT_TEST_ASSERT(head->next == head);
|
||||
UNIT_TEST_ASSERT(tail->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == tail);
|
||||
|
||||
/*
|
||||
* Add an item by adding to the tail.
|
||||
* (tail) <--> 0 <--> 1 <--> (head)
|
||||
* Head should point to tail in both directions
|
||||
*/
|
||||
dbl_circ_list_add_tail(cdll, &elements[1]);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 2);
|
||||
UNIT_TEST_ASSERT(head == &elements[0]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->next == tail);
|
||||
UNIT_TEST_ASSERT(tail->previous == head);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
|
||||
/*
|
||||
* Add before head.
|
||||
* (tail) <--> 2 <--> 0 <--> 1 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_add_before(cdll, dbl_circ_list_head(cdll), &elements[2]);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 3);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[2].previous == tail);
|
||||
UNIT_TEST_ASSERT(elements[2].next == &elements[0]);
|
||||
UNIT_TEST_ASSERT(elements[0].previous == head);
|
||||
|
||||
/*
|
||||
* Add after head.
|
||||
* (tail) <--> 2 <--> 3 <--> 0 <--> 1 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_add_after(cdll, dbl_circ_list_head(cdll), &elements[3]);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 4);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[3].previous == head);
|
||||
UNIT_TEST_ASSERT(elements[3].next == &elements[0]);
|
||||
UNIT_TEST_ASSERT(elements[0].previous == &elements[3]);
|
||||
|
||||
/*
|
||||
* Add at 3rd position by adding after 2nd
|
||||
* (tail) <--> 2 <--> 3 <--> 4 <--> 0 <--> 1 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_add_after(cdll, &elements[3], &elements[4]);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 5);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[3].next == &elements[4]);
|
||||
UNIT_TEST_ASSERT(elements[4].previous == &elements[3]);
|
||||
UNIT_TEST_ASSERT(elements[4].next == &elements[0]);
|
||||
UNIT_TEST_ASSERT(elements[0].previous == &elements[4]);
|
||||
|
||||
/*
|
||||
* Add at 3rd position by adding before 3rd
|
||||
* (tail) <--> 2 <--> 3 <--> 5 <--> 4 <--> 0 <--> 1 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_add_before(cdll, &elements[4], &elements[5]);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 6);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[3].next == &elements[5]);
|
||||
UNIT_TEST_ASSERT(elements[5].previous == &elements[3]);
|
||||
UNIT_TEST_ASSERT(elements[5].next == &elements[4]);
|
||||
UNIT_TEST_ASSERT(elements[4].previous == &elements[5]);
|
||||
|
||||
/*
|
||||
* Add before tail
|
||||
* (tail) <--> 2 <--> 3 <--> 5 <--> 4 <--> 0 <--> 6 <--> 1 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_add_before(cdll, dbl_circ_list_tail(cdll), &elements[6]);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 7);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[1]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[0].next == &elements[6]);
|
||||
UNIT_TEST_ASSERT(elements[6].previous == &elements[0]);
|
||||
UNIT_TEST_ASSERT(elements[6].next == &elements[1]);
|
||||
UNIT_TEST_ASSERT(elements[1].previous == &elements[6]);
|
||||
|
||||
/*
|
||||
* Add after tail
|
||||
* (tail) <--> 2 <--> 3 <--> 5 <--> 4 <--> 0 <--> 6 <--> 1 <--> 7 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_add_after(cdll, dbl_circ_list_tail(cdll), &elements[7]);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 8);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[7]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[1].next == &elements[7]);
|
||||
UNIT_TEST_ASSERT(elements[7].previous == &elements[1]);
|
||||
UNIT_TEST_ASSERT(elements[7].next == &elements[2]);
|
||||
UNIT_TEST_ASSERT(elements[2].previous == &elements[7]);
|
||||
|
||||
/*
|
||||
* Find and remove element 5
|
||||
* (tail) <--> 2 <--> 3 <--> 4 <--> 0 <--> 6 <--> 1 <--> 7 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_remove(cdll, &elements[5]);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 7);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[7]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[3].next == &elements[4]);
|
||||
UNIT_TEST_ASSERT(elements[4].previous == &elements[3]);
|
||||
|
||||
/*
|
||||
* Find element 4 and remove what's after it
|
||||
* (tail) <--> 2 <--> 3 <--> 4 <--> 6 <--> 1 <--> 7 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_remove(cdll, elements[4].next);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 6);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[7]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[4].next == &elements[6]);
|
||||
UNIT_TEST_ASSERT(elements[6].previous == &elements[4]);
|
||||
|
||||
/*
|
||||
* Find element 4 and remove what's before it
|
||||
* (tail) <--> 2 <--> 4 <--> 6 <--> 1 <--> 7 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_remove(cdll, elements[4].previous);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 5);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[7]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[2].next == &elements[4]);
|
||||
UNIT_TEST_ASSERT(elements[4].previous == &elements[2]);
|
||||
|
||||
/*
|
||||
* Remove before tail
|
||||
* (tail) <--> 2 <--> 4 <--> 6 <--> 7 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_remove(cdll,
|
||||
((demo_struct_t *)dbl_circ_list_tail(cdll))->previous);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 4);
|
||||
UNIT_TEST_ASSERT(head == &elements[2]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[7]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[6].next == &elements[7]);
|
||||
UNIT_TEST_ASSERT(elements[7].previous == &elements[6]);
|
||||
|
||||
/*
|
||||
* Remove after tail
|
||||
* (tail) <--> 4 <--> 6 <--> 7 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_remove(cdll,
|
||||
((demo_struct_t *)dbl_circ_list_tail(cdll))->next);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 3);
|
||||
UNIT_TEST_ASSERT(head == &elements[4]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[7]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
UNIT_TEST_ASSERT(elements[7].next == &elements[4]);
|
||||
UNIT_TEST_ASSERT(elements[4].previous == &elements[7]);
|
||||
|
||||
/*
|
||||
* Remove after head
|
||||
* (tail) <--> 4 <--> 7 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_remove(cdll,
|
||||
((demo_struct_t *)dbl_circ_list_head(cdll))->next);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 2);
|
||||
UNIT_TEST_ASSERT(head == &elements[4]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[7]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(head->next == tail);
|
||||
UNIT_TEST_ASSERT(tail->previous == head);
|
||||
UNIT_TEST_ASSERT(tail->next == head);
|
||||
|
||||
/*
|
||||
* Remove before head
|
||||
* (tail) <--> 4 <--> (head)
|
||||
*/
|
||||
dbl_circ_list_remove(cdll,
|
||||
((demo_struct_t *)dbl_circ_list_head(cdll))->previous);
|
||||
head = dbl_circ_list_head(cdll);
|
||||
tail = dbl_circ_list_tail(cdll);
|
||||
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 1);
|
||||
UNIT_TEST_ASSERT(head == &elements[4]);
|
||||
UNIT_TEST_ASSERT(tail == &elements[4]);
|
||||
UNIT_TEST_ASSERT(head->previous == tail);
|
||||
UNIT_TEST_ASSERT(head->next == tail);
|
||||
|
||||
/* Remove head */
|
||||
dbl_circ_list_remove(cdll, dbl_circ_list_head(cdll));
|
||||
dbl_circ_list_remove(cdll, dbl_circ_list_head(cdll));
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == true);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 0);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_head(cdll) == NULL);
|
||||
UNIT_TEST_ASSERT(dbl_circ_list_tail(cdll) == NULL);
|
||||
|
||||
UNIT_TEST_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(data_structure_test_process, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
|
||||
printf("Run unit-test\n");
|
||||
printf("---\n");
|
||||
|
||||
memset(elements, 0, sizeof(elements));
|
||||
|
||||
UNIT_TEST_RUN(test_stack);
|
||||
UNIT_TEST_RUN(test_queue);
|
||||
UNIT_TEST_RUN(test_csll);
|
||||
UNIT_TEST_RUN(test_dll);
|
||||
UNIT_TEST_RUN(test_cdll);
|
||||
|
||||
printf("=check-me= DONE\n");
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
25
tests/07-simulation-base/js/data-structures.js
Normal file
25
tests/07-simulation-base/js/data-structures.js
Normal file
@ -0,0 +1,25 @@
|
||||
TIMEOUT(10000, log.testFailed());
|
||||
|
||||
var failed = false;
|
||||
|
||||
while(true) {
|
||||
YIELD();
|
||||
|
||||
log.log(time + " " + "node-" + id + " "+ msg + "\n");
|
||||
|
||||
if(msg.contains("=check-me=") == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(msg.contains("FAILED")) {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if(msg.contains("DONE")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(failed) {
|
||||
log.testFailed();
|
||||
}
|
||||
log.testOK();
|
40
tests/08-native-runs/01-test-data-structures.sh
Executable file
40
tests/08-native-runs/01-test-data-structures.sh
Executable file
@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Contiki directory
|
||||
CONTIKI=$1
|
||||
|
||||
# Example code directory
|
||||
CODE_DIR=$CONTIKI/tests/07-simulation-base/code-data-structures/
|
||||
CODE=test-data-structures
|
||||
|
||||
# Starting Contiki-NG native node
|
||||
echo "Starting native node"
|
||||
make -C $CODE_DIR TARGET=native > make.log 2> make.err
|
||||
$CODE_DIR/$CODE.native > $CODE.log 2> $CODE.err &
|
||||
CPID=$!
|
||||
sleep 2
|
||||
|
||||
echo "Closing native node"
|
||||
sleep 2
|
||||
pgrep $CODE | xargs kill -9
|
||||
|
||||
if grep -q "=check-me= FAILED" $CODE.log ; then
|
||||
echo "==== make.log ====" ; cat make.log;
|
||||
echo "==== make.err ====" ; cat make.err;
|
||||
echo "==== $CODE.log ====" ; cat $CODE.log;
|
||||
echo "==== $CODE.err ====" ; cat $CODE.err;
|
||||
|
||||
printf "%-32s TEST FAIL\n" "$CODE" | tee $CODE.testlog;
|
||||
else
|
||||
cp $CODE.log $CODE.testlog
|
||||
printf "%-32s TEST OK\n" "$CODE" | tee $CODE.testlog;
|
||||
fi
|
||||
|
||||
rm make.log
|
||||
rm make.err
|
||||
rm $CODE.log
|
||||
rm $CODE.err
|
||||
|
||||
# We do not want Make to stop -> Return 0
|
||||
# The Makefile will check if a log contains FAIL at the end
|
||||
exit 0
|
1
tests/08-native-runs/Makefile
Normal file
1
tests/08-native-runs/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../Makefile.script-test
|
@ -41,10 +41,10 @@ define dooneexample
|
||||
@echo -n Building example $(3): $(1) $(4) for target $(2)
|
||||
@((cd $(EXAMPLESDIR)/$(1); \
|
||||
make $(4) TARGET=$(2) clean && make -j $(4) TARGET=$(2) WERROR=1) > \
|
||||
/dev/null 2>make.runerr && \
|
||||
/dev/null 2>make.err && \
|
||||
(echo " -> OK" && printf "%-75s %-35s %-20s TEST OK\n" "$(1)" "$(4)" "$(2)" > $(3)-$(subst /,-,$(1))$(2).testlog) || \
|
||||
(echo " -> FAIL" && printf "%-75s %-35s %-20s TEST FAIL\n" "$(1)" "$(4)" "$(2)" > $(3)-$(subst /,-,$(1))$(2).testlog ; cat make.runerr))
|
||||
@rm -f make.runerr
|
||||
(echo " -> FAIL" && printf "%-75s %-35s %-20s TEST FAIL\n" "$(1)" "$(4)" "$(2)" > $(3)-$(subst /,-,$(1))$(2).testlog ; cat make.err))
|
||||
@rm -f make.err
|
||||
endef
|
||||
|
||||
define doexample
|
||||
|
Loading…
Reference in New Issue
Block a user