
52 changed files with 3531 additions and 43 deletions
@ -0,0 +1,5 @@
|
||||
MODULE =core
|
||||
|
||||
INCLUDES = -Iinclude/ -I../sys/include -I../sys/lib -I../sys/drivers/include -I../cpu/$(CPU)/include/ -I../..
|
||||
|
||||
include $(RIOTBASE)/makefile.base |
@ -0,0 +1,7 @@
|
||||
MODULE =arm_common
|
||||
INCLUDES = -Iinclude -I../$(CPU)/include -I../../sys/lib -I../../drivers/include -I../../core/include -I../../sys/include -I../../hal/include -I../../.. -I../../sys/lib/fat
|
||||
|
||||
include $(RIOTBASE)/makefile.base |
||||
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
MODULE =cpu
|
||||
|
||||
INCLUDES = -Iinclude -Idrivers/include -I../arm_common/include -I../../sys/lib -I../../sys/drivers/include -I../../core/include -I../../sys/include -I../../hal/include -I../../..
|
||||
DIRS =
|
||||
|
||||
all: $(BINDIR)$(MODULE).a |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i ; done ;
|
||||
|
||||
include $(RIOTBASE)/makefile.base |
||||
|
||||
clean:: |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i clean ; done ;
|
||||
|
@ -0,0 +1,32 @@
|
||||
SRC = blocklist.c kernel_init.c msg.c scheduler.c blocklist_malloc.c ktimer.c mutex.c thread.c clist.c queue.c
|
||||
OBJ = $(SRC:%.c=../bin/%.o)
|
||||
|
||||
INCLUDES = -Iinclude/ -I../sys/include -I../sys/lib -I../sys/drivers/include -I../cpu/$(CPU)/include/
|
||||
|
||||
ifeq ($(CPU),lpc2387) |
||||
INCLUDES += -I../cpu/arm_common/include/
|
||||
CPUINCLUDE = -includecpu-conf.h
|
||||
endif |
||||
ifeq ($(CPU),lpc214x) |
||||
INCLUDES += -I../cpu/arm_common/include/
|
||||
endif |
||||
|
||||
../bin/core.a: $(OBJ) |
||||
$(AR) rcs ../bin/core.a $(OBJ)
|
||||
|
||||
# pull in dependency info for *existing* .o files
|
||||
-include $(OBJ:.o=.d) |
||||
|
||||
# compile and generate dependency info
|
||||
../bin/%.o: %.c |
||||
$(CC) $(CFLAGS) $(INCLUDES) $(BOARDINCLUDE) $(PROJECTINCLUDE) $(CPUINCLUDE) -c $*.c -o ../bin/$*.o
|
||||
$(CC) $(CFLAGS) $(INCLUDES) $(BOARDINCLUDE) $(PROJECTINCLUDE) $(CPUINCLUDE) -MM $*.c > ../bin/$*.d
|
||||
@printf "../bin/"|cat - ../bin/$*.d > /tmp/fw_out && mv /tmp/fw_out ../bin/$*.d
|
||||
|
||||
# remove compilation products
|
||||
clean: |
||||
rm -f ../bin/core.a ../bin/*.o ../bin/*.d
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
MODULE =cpu
|
||||
|
||||
INCLUDES = -Iinclude -Idrivers/include -I../arm_common/include -I../../sys/lib -I../../drivers/include -I../../core/include -I../../sys/include -I../../hal/include -I../../..
|
||||
DIRS =
|
||||
|
||||
all: $(BINDIR)$(MODULE).a |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i ; done ;
|
||||
|
||||
include $(RIOTBASE)/makefile.base |
||||
|
||||
clean:: |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i clean ; done ;
|
||||
|
@ -0,0 +1,29 @@
|
||||
ifeq ($(CPU),lpc2387) |
||||
DIRS = arm_common lpc2387
|
||||
endif |
||||
|
||||
ifeq ($(CPU),lpc214x) |
||||
DIRS = arm_common lpc214x
|
||||
endif |
||||
|
||||
ifeq ($(CPU),cc430) |
||||
DIRS = msp430 cc430
|
||||
endif |
||||
|
||||
.PHONY: cpus |
||||
.PHONY: $(DIRS) |
||||
|
||||
cpus: $(DIRS) |
||||
|
||||
$(DIRS): |
||||
@$(MAKE) -C $@
|
||||
|
||||
clean: |
||||
@$(MAKE) -C lpc2387 clean
|
||||
@$(MAKE) -C arm_common clean
|
||||
@$(MAKE) -C cc430 clean
|
||||
@$(MAKE) -C msp430-common clean
|
||||
@$(MAKE) -C msp430x16x clean
|
||||
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
MODULE =cpu
|
||||
|
||||
INCLUDES = -Iinclude -Idrivers/include -I../arm_common/include -I../../sys/lib -I../../sys/drivers/include -I../../core/include -I../../sys/include -I../../hal/include -I../../..
|
||||
DIRS =
|
||||
|
||||
all: $(BINDIR)$(MODULE).a |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i ; done ;
|
||||
|
||||
include $(RIOTBASE)/makefile.base |
||||
|
||||
clean:: |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i clean ; done ;
|
||||
|
@ -0,0 +1,7 @@
|
||||
INCLUDES = -I../../include -I../../net -I../include -I../../lib -I../../../.. -I../../../cpu/ -I../../../core/include -I../../
|
||||
|
||||
MODULE =cc110x
|
||||
|
||||
include $(MAKEBASE)/makefile.base |
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
INCLUDES = -I../../include -I../../net -I../include -I../../lib -I../../../.. -I../../../cpu/ -I../../../core/include -I../../ -Iinclude/
|
||||
MODULE =cc110x_ng
|
||||
include $(MAKEBASE)/makefile.base |
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
INCLUDES = -I../../include -I../../lib -I../../../cpu/$(CPU)/include -I../../../cpu/ -I../../../hal/include -I../../../core/include -I../../config -I../include
|
||||
MODULE =ltc4150
|
||||
include $(MAKEBASE)/makefile.base |
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
DIRS=
|
||||
ifneq (,$(findstring powermon,$(USEMODULE))) |
||||
DIRS += powermon
|
||||
endif |
||||
ifneq (,$(findstring sht11,$(USEMODULE))) |
||||
DIRS += sht11
|
||||
endif |
||||
ifneq (,$(findstring ltc4150,$(USEMODULE))) |
||||
DIRS += ltc4150
|
||||
endif |
||||
ifneq (,$(findstring cc110x,$(USEMODULE))) |
||||
ifneq (,$(findstring cc110x_ng,$(USEMODULE)))
|
||||
DIRS += cc110x_ng
|
||||
else
|
||||
DIRS += cc110x
|
||||
endif
|
||||
endif |
||||
ifneq (,$(findstring gps_ublox,$(USEMODULE))) |
||||
DIRS += gps_ublox
|
||||
endif |
||||
ifneq (,$(findstring cc110x_ng,$(USEMODULE))) |
||||
DIRS += cc110x_ng
|
||||
endif |
||||
|
||||
all: |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i ; done ;
|
||||
|
||||
include $(RIOTBASE)/makefile.base |
||||
|
||||
# remove compilation products
|
||||
clean:: |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i clean ; done ;
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
INCLUDES = -I../../include -I../../lib -I../../../cpu/$(CPU)/include -I../../../cpu/ -I../../../hal/include -I../../../core/include -I../../config -I../include
|
||||
MODULE =sht11
|
||||
include $(MAKEBASE)/makefile.base |
||||
|
||||
|
@ -0,0 +1,9 @@
|
||||
DIRS = cpu core drivers sys
|
||||
|
||||
all: |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i ; done ;
|
||||
|
||||
clean: |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i clean ; done ;
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
ASMSRC = $(wildcard *.s) |
||||
ASMOBJ = $(ASMSRC:%.s=$(BINDIR)%.o) |
||||
SRC = $(wildcard *.c) |
||||
OBJ = $(SRC:%.c=$(BINDIR)%.o) |
||||
DEP = $(SRC:%.c=$(BINDIR)%.d) |
||||
|
||||
ifeq ($(CPU),lpc2387) |
||||
INCLUDES += -I$(MAKEBASE)/cpu/arm_common/include/ |
||||
INCLUDES += -I$(MAKEBASE)/cpu/lpc2387/include |
||||
endif |
||||
ifeq ($(CPU),lpc214x) |
||||
INCLUDES += -I$(MAKEBASE)/cpu/arm_common/include/ |
||||
INCLUDES += -I$(MAKEBASE)/cpu/lpc214x/include |
||||
endif |
||||
ifeq ($(CPU),msp430x16x) |
||||
INCLUDES += -I$(MAKEBASE)/cpu/msp430-common/include/ |
||||
INCLUDES += -I$(MAKEBASE)/cpu/msp430x16x/include/ |
||||
endif |
||||
ifeq ($(CPU),cc430) |
||||
INCLUDES += -I$(MAKEBASE)/cpu/msp430-common/include/ |
||||
INCLUDES += -I$(MAKEBASE)/cpu/cc430/include/ |
||||
endif |
||||
|
||||
$(BINDIR)$(MODULE).a: $(OBJ) $(ASMOBJ) |
||||
$(AR) -rc $(BINDIR)$(MODULE).a $(OBJ) $(ASMOBJ) |
||||
|
||||
# pull in dependency info for *existing* .o files |
||||
-include $(OBJ:.o=.d) |
||||
|
||||
# compile and generate dependency info |
||||
$(BINDIR)%.o: %.c |
||||
$(CC) $(CFLAGS) $(PROJECTINCLUDE) $(BOARDINCLUDE) $(INCLUDES) -c $*.c -o $(BINDIR)$*.o |
||||
$(CC) $(CFLAGS) $(PROJECTINCLUDE) $(BOARDINCLUDE) $(INCLUDES) -MM $*.c > $(BINDIR)$*.d |
||||
@printf "$(BINDIR)"|cat - $(BINDIR)$*.d > /tmp/riot_out && mv /tmp/riot_out $(BINDIR)$*.d |
||||
|
||||
$(BINDIR)%.o: %.s |
||||
$(AS) $(ASFLAGS) $*.s -o $(BINDIR)$*.o |
||||
|
||||
# remove compilation products |
||||
clean:: |
||||
rm -f $(BINDIR)$(MODULE).a $(OBJ) $(DEP) $(ASMOBJ) |
||||
|
@ -0,0 +1,26 @@
|
||||
export MAKEBASE =$(RIOTBASE) |
||||
export BINDIR =$(RIOTBASE)/bin/ |
||||
#UNDEF = $(BINDIR)startup.o $(BINDIR)builddate.o |
||||
UNDEF = $(BINDIR)startup.o |
||||
|
||||
### Minimal setup |
||||
ifeq ($(CPU),lpc2387) |
||||
USEMODULE += arm_common |
||||
UNDEF += $(BINDIR)syscalls.o |
||||
endif |
||||
ifeq ($(CPU),lpc214x) |
||||
USEMODULE += arm_common |
||||
UNDEF += $(BINDIR)syscalls.o |
||||
endif |
||||
ifeq ($(CPU),cc430) |
||||
USEMODULE += cpu core lib sys |
||||
else |
||||
#USEMODULE += cpu_drivers cpu core lib sys |
||||
USEMODULE += cpu core sys |
||||
endif |
||||
ED = $(USEMODULE:%=-D MODULE_%) |
||||
EXTDEFINES = $(shell echo $(ED)|tr 'a-z' 'A-Z') |
||||
export BASELIBS=$(USEMODULE:%= $(BINDIR)%.a) |
||||
CFLAGS += $(EXTDEFINES) |
||||
|
||||
export USEMODULE |
@ -0,0 +1,6 @@
|
||||
INCLUDES = -I../include -I../drivers/include -I../lib -I../../cpu/$(CPU)/include -I../../cpu/ -I../lib/cmdengine -I../net -I../../hal/include -I../../core/include -I../config
|
||||
MODULE =shell
|
||||
|
||||
include $(RIOTBASE)/makefile.base |
||||
|
||||
|
@ -0,0 +1,193 @@
|
||||
/******************************************************************************
|
||||
Copyright 2009-2010, Freie Universitaet Berlin (FUB). All rights reserved. |
||||
|
||||
These sources were developed at the Freie Universitaet Berlin, Computer Systems |
||||
and Telematics group (http://cst.mi.fu-berlin.de).
|
||||
------------------------------------------------------------------------------- |
||||
This file is part of FeuerWare. |
||||
|
||||
This program is free software: you can redistribute it and/or modify it under |
||||
the terms of the GNU General Public License as published by the Free Software |
||||
Foundation, either version 3 of the License, or (at your option) any later |
||||
version. |
||||
|
||||
FeuerWare is distributed in the hope that it will be useful, but WITHOUT |
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License along with |
||||
this program. If not, see http://www.gnu.org/licenses/ .
|
||||
-------------------------------------------------------------------------------- |
||||
For further information and questions please use the web site |
||||
http://scatterweb.mi.fu-berlin.de
|
||||
and the mailinglist (subscription via web site) |
||||
scatterweb@lists.spline.inf.fu-berlin.de |
||||
*******************************************************************************/ |
||||
|
||||
/**
|
||||
* @file |
||||
* @brief Simple logging demon implementation |
||||
* |
||||
* @author Freie Universitรคt Berlin, Computer Systems & Telematics, FeuerWhere project |
||||
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de> |
||||
* @version $Revision: 3854 $ |
||||
* |
||||
* @note $Id: logd.c 3854 2011-12-06 15:27:01Z hwill $ |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <fcntl.h> |
||||
#include <string.h> |
||||
// core
|
||||
#include "msg.h" |
||||
#include "flags.h" |
||||
#include "mutex.h" |
||||
#include "thread.h" |
||||
#include "kernel.h" |
||||
// system
|
||||
#include "logd.h" |
||||
#include "list.h" |
||||
|
||||
typedef struct log_queue_t |
||||
{ |
||||
list_node_t listnode; |
||||
char* str; |
||||
int str_len; |
||||
} log_queue_t; |
||||
|
||||
static volatile int log_pid = -1; |
||||
static int logd_stack_size = LOGD_STACK_SIZE_NORMAL; |
||||
static FILE* fh = NULL; |
||||
static int log_count = 0; |
||||
static mutex_t log_mutex; |
||||
static list_t log_msg_queue; |
||||
static volatile bool exit_flag = false; |
||||
static volatile bool echo_on = false; |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
static void close_file_handle(void) |
||||
{ |
||||
if (fh != NULL) { |
||||
fclose(fh); |
||||
fh = NULL; |
||||
} |
||||
} |
||||
|
||||
static void write_to_file(char* str, int str_len) |
||||
{ |
||||
if (fh != NULL && str_len > 0) { |
||||
if (fwrite(str, sizeof(char), str_len, fh) != str_len) { |
||||
if (echo_on && logd_stack_size >= LOGD_STACK_SIZE_CONSOLE) { |
||||
printf("LOGD [WARN]: file write failed, closing file\n"); |
||||
} |
||||
close_file_handle(); |
||||
return; |
||||
} |
||||
if (fflush(fh) == EOF) { |
||||
if (echo_on && logd_stack_size >= LOGD_STACK_SIZE_CONSOLE) { |
||||
printf("LOGD [WARN]: file write failed, closing file\n"); |
||||
} |
||||
close_file_handle(); |
||||
return; |
||||
} |
||||
} else { |
||||
fh = fopen("/LOGD.LOG", "w"); |
||||
if (!fh) { |
||||
if (echo_on && logd_stack_size >= LOGD_STACK_SIZE_CONSOLE) { |
||||
printf("LOGD [WARN]: file reopen failed, damn!\n"); |
||||
} |
||||
} else { |
||||
write_to_file(str, str_len); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void logd_process(void) |
||||
{ |
||||
msg m; |
||||
log_queue_t* node; |
||||
do |
||||
{ |
||||
if (!exit_flag) msg_receive(&m); |
||||
mutex_lock(&log_mutex); |
||||
while ((node = (log_queue_t*) list_remove_head(&log_msg_queue)) != NULL) { |
||||
write_to_file(node->str, node->str_len); |
||||
if (echo_on && logd_stack_size >= LOGD_STACK_SIZE_CONSOLE) { |
||||
printf("%s", node->str); |
||||
} |
||||
log_count++; |
||||
free(node->str); |
||||
free(node); |
||||
} |
||||
mutex_unlock(&log_mutex, 0); |
||||
} while (m.type != MSG_EXIT && !exit_flag); |
||||
/* Logging thread is terminating, close log file */ |
||||
close_file_handle(); |
||||
} |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
static void logd_init0(void) { |
||||
fh = fopen("/LOGD.LOG", "w"); |
||||
if (!fh) return; |
||||
log_pid = thread_create(logd_stack_size, PRIORITY_LOGD, CREATE_STACKTEST, logd_process, "logd"); |
||||
} |
||||
|
||||
void logd_init(int stack_size) |
||||
{ |
||||
logd_stack_size = stack_size; |
||||
mutex_init(&log_mutex); |
||||
list_init(&log_msg_queue); |
||||
logd_init0(); |
||||
} |
||||
|
||||
void logd_set_console_enabled(bool enabled) |
||||
{ |
||||
echo_on = enabled; |
||||
} |
||||
|
||||
bool logd_log(char* str, int str_len) |
||||
{ |
||||
msg m; |
||||
// Test if logd process was created
|
||||
if (log_pid == -1) { |
||||
// no logd created, because fopen() on log file failed. So try again
|
||||
logd_init0(); |
||||
if (log_pid == -1) { |
||||
// Still errors opening log file, exit now
|
||||
return false; |
||||
} |
||||
} |
||||
log_queue_t* lq = malloc(sizeof(*lq)); |
||||
if (lq == NULL) return false; |
||||
lq->str = malloc(sizeof(char) * str_len + 1); // 1 byte for string termination char
|
||||
if (lq->str == NULL) { |
||||
free(lq); |
||||
return false; |
||||
} |
||||
strncpy(lq->str, str, str_len); |
||||
lq->str_len = str_len; |
||||
lq->str[str_len] = '\0'; // add string termination char at end of buffer
|
||||
mutex_lock(&log_mutex); |
||||
list_append(&log_msg_queue, (list_node_t*) lq); |
||||
mutex_unlock(&log_mutex, 0); |
||||
m.type = MSG_POLL; |
||||
m.content.ptr = NULL; |
||||
msg_send(&m, log_pid, false); |
||||
return true; |
||||
} |
||||
|
||||
void logd_exit(void) |
||||
{ |
||||
msg m; |
||||
// Test if logd process was created
|
||||
if (log_pid == -1) { |
||||
return; |
||||
} |
||||
exit_flag = true; |
||||
m.type = MSG_EXIT; |
||||
m.content.ptr = NULL; |
||||
msg_send(&m, log_pid, false); |
||||
} |
@ -0,0 +1,7 @@
|
||||
INCLUDES = -I../include -I../drivers/include -I../lib -I../../cpu/$(CPU)/include -I../../cpu/ -I../lib/cmdengine -I../net -I../../hal/include -I../../core/include -I../config
|
||||
|
||||
MODULE =logd
|
||||
|
||||
include $(MAKEBASE)/makefile.base |
||||
|
||||
|
@ -0,0 +1,58 @@
|
||||
|
||||
INCLUDES = -Iinclude -I$(RIOTBASE)/drivers/ -I$(RIOTBASE)/drivers/include -Ilib -I../.. -I../cpu/$(CPU)/include -I../cpu/ -Ilib/cmdengine -Inet -I../hal/include -I../core/include -Iconfig
|
||||
|
||||
MODULE =sys
|
||||
ifneq (,$(findstring config,$(USEMODULE))) |
||||
DIRS += config
|
||||
endif |
||||
ifneq (,$(findstring net,$(USEMODULE))) |
||||
DIRS += net
|
||||
endif |
||||
ifneq (,$(findstring lib,$(USEMODULE))) |
||||
DIRS += lib
|
||||
endif |
||||
ifneq (,$(findstring logd,$(USEMODULE))) |
||||
DIRS += logd
|
||||
endif |
||||
ifneq (,$(findstring cmdd,$(USEMODULE))) |
||||
DIRS += cmdd
|
||||
endif |
||||
ifneq (,$(findstring mprint,$(USEMODULE))) |
||||
DIRS += mprint
|
||||
endif |
||||
ifneq (,$(findstring sync_read,$(USEMODULE))) |
||||
DIRS += sync_read
|
||||
endif |
||||
ifneq (,$(findstring syslog,$(USEMODULE))) |
||||
DIRS += syslog
|
||||
endif |
||||
ifneq (,$(findstring sysmon,$(USEMODULE))) |
||||
DIRS += sysmon
|
||||
endif |
||||
ifneq (,$(findstring utimer,$(USEMODULE))) |
||||
DIRS += utimer
|
||||
endif |
||||
ifneq (,$(findstring mqueue,$(USEMODULE))) |
||||
DIRS += mqueue
|
||||
endif |
||||
ifneq (,$(findstring shell,$(USEMODULE))) |
||||
DIRS += shell
|
||||
endif |
||||
ifneq (,$(findstring tracelog,$(USEMODULE))) |
||||
DIRS += tracelog
|
||||
endif |
||||
ifneq (,$(findstring transceiver,$(USEMODULE))) |
||||
DIRS += transceiver
|
||||
endif |
||||
|
||||
all: $(BINDIR)$(MODULE).a |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i ; done ;
|
||||
|
||||
include $(RIOTBASE)/makefile.base |
||||
|
||||
# remove compilation products
|
||||
clean:: |
||||
@for i in $(DIRS) ; do $(MAKE) -C $$i clean ; done ;
|
||||
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
# ****************************************************************************** |
||||
# Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. |
||||
# |
||||
# These sources were developed at the Freie Universitaet Berlin, Computer |
||||
# Systems and Telematics group (http://cst.mi.fu-berlin.de). |
||||
# ------------------------------------------------------------------------------ |
||||
# This file is part of FeuerWare. |
||||
# |
||||
# This program is free software: you can redistribute it and/or modify it under |
||||
# the terms of the GNU General Public License as published by the Free Software |
||||
# Foundation, either version 3 of the License, or (at your option) any later |
||||
# version. |
||||
# |
||||
# FeuerWare is distributed in the hope that it will be useful, but WITHOUT |
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License along with |
||||
# this program. If not, see http://www.gnu.org/licenses/ . |
||||
# ------------------------------------------------------------------------------ |
||||
# For further information and questions please use the web site |
||||
# http://scatterweb.mi.fu-berlin.de |
||||
# and the mailinglist (subscription via web site) |
||||
# scatterweb@lists.spline.inf.fu-berlin.de |
||||
# ****************************************************************************** |
||||
# $Id: Jamfile 1253 2009-08-25 10:31:47Z hillebra $ |
||||
|
||||
SubDir TOP sys net mm ; |
||||
|
||||
Module net_mm : mmr.c mmstack.c : net_kernel ; |
||||
|
@ -0,0 +1,6 @@
|
||||
INCLUDES = -I.. -I../../include -I../../drivers/include -I../../../core/include -I../../lib -I../../lib/cmdengine -I../../../hal/include
|
||||
|
||||
MODULE =net_mm
|
||||
|
||||
include $(MAKEBASE)/makefile.base
|
||||
|
@ -0,0 +1,907 @@
|
||||
/******************************************************************************
|
||||
Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. |
||||
|
||||
These sources were developed at the Freie Universitaet Berlin, Computer Systems |
||||
and Telematics group (http://cst.mi.fu-berlin.de).
|
||||
------------------------------------------------------------------------------- |
||||
This file is part of FeuerWare. |
||||
|
||||
This program is free software: you can redistribute it and/or modify it under |
||||
the terms of the GNU General Public License as published by the Free Software |
||||
Foundation, either version 3 of the License, or (at your option) any later |
||||
version. |
||||
|
||||
FeuerWare is distributed in the hope that it will be useful, but WITHOUT |
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License along with |
||||
this program. If not, see http://www.gnu.org/licenses/ .
|
||||
-------------------------------------------------------------------------------- |
||||
For further information and questions please use the web site |
||||
http://scatterweb.mi.fu-berlin.de
|
||||
and the mailinglist (subscription via web site) |
||||
scatterweb@lists.spline.inf.fu-berlin.de |
||||
*******************************************************************************/ |
||||
|
||||
/**
|
||||
* @file |
||||
* @internal |
||||
* @brief Micro Mesh Routing |
||||
* |
||||
* @author Freie Universitรคt Berlin, Computer Systems & Telematics, FeuerWhere project |
||||
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de> |
||||
* @version $Revision: 3854 $ |
||||
* |
||||
* @note $Id: mmr.c 3854 2011-12-06 15:27:01Z hwill $ |
||||
*/ |
||||
|
||||
#include "configure.h" |
||||
#include "mmr.h" |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include "net.h" |
||||
|
||||
#include "clock.h" |
||||
#include "utimer.h" |
||||
#include "kernel.h" |
||||
#include "thread.h" |
||||
#include "msg.h" |
||||
|
||||
#define LEVEL_INFO 2 ///< All messages are printed
|
||||
#define LEVEL_WARN 1 ///< Only warnings and error messages are printed
|
||||
#define LEVEL_ERROR 0 ///< Only error messages are printed
|
||||
#define MMR_INFO_LEVEL LEVEL_WARN ///< Current information level
|
||||
|
||||
#define DEBUG(...) |
||||
//#define DEBUG(...) printf(__VA_ARGS__)
|
||||
|
||||
#define CONSTANT_SECOND (1) |
||||
|
||||
#define RREQ_ID_SEQUENCE_NUMBER_START (1) |
||||
#define RREQ_THRESHOLD (3) |
||||
#define RREQ_NONE (0xFF) // Send no RREQs for these messages, value
|
||||
// must be greater than RREQ_THRESHOLD
|
||||
|
||||
#define TTL_START (1) |
||||
#define TTL_THRESHOLD (10) |
||||
|
||||
#define RREQ_TIMEOUT_BASE (2*CONSTANT_SECOND) |
||||
#define RREQ_TIMEOUT_PER_TTL (1*CONSTANT_SECOND) |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
// Message queue data structures
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
#define MESSAGE_QUEUE_SIZE (20) |
||||
|
||||
typedef struct message_queue_entry_t |
||||
{ |
||||
net_message_t message; |
||||
volatile uint32_t timestamp; |
||||
uint8_t retry_count; |
||||
} message_queue_entry_t; |
||||
|
||||
static message_queue_entry_t message_queue[MESSAGE_QUEUE_SIZE]; |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
// RREQ-Timeout data structures
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
static struct utimer ut; |
||||
static volatile bool rreq_to_active = false; // RREQ timeout active bit
|
||||
static const char *rreq_timeout_process_name = "mmrd"; |
||||
static uint16_t rreq_timeout_process_pid; |
||||
static void rreq_timeout_process(void); |
||||
static void post_next_rreq_timeout(void); |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
// Statistic data structures
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
typedef struct mmr_stat |
||||
{ |
||||
uint32_t rreq_originated; |
||||
uint32_t rrep_originated; |
||||
uint32_t rerr_originated; |
||||
uint32_t rreq_received; |
||||
uint32_t rrep_received; |
||||
uint32_t rerr_received; |
||||
uint32_t messages_no_route_found; // RREQ found no route
|
||||
uint32_t messages_no_route_avail_on_forward; // Forwarding: no route in route table
|
||||
uint32_t messages_broken_link_on_forward; // Forwarding: broken link detected
|
||||
uint32_t rreq_duplicated; |
||||
} mmr_stat_t; |
||||
|
||||
static mmr_stat_t mmr_stats; |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
/**
|
||||
* Returns time of RTC in seconds. |
||||
* |
||||
* @return Time of RTC in seconds |
||||
*/ |
||||
static uint32_t rtc_now(void) |
||||
{ |
||||
return (uint32_t)(clock_get_systemtime()/1000); |
||||
} |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
// Routing table management
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
/**
|
||||
* @brief Extract route information and store them in route table. |
||||
* |
||||
* @param local_addr Local network address of this node |
||||
* @param length Length of address list |
||||
* @param list Address list with route information |
||||
*/ |
||||
static void rt_extract_routes(uint16_t local_addr, uint8_t length, uint16_t* list) |
||||
{ |
||||
DEBUG("call [%u]: rt_extract_routes\n", fk_thread->pid); |
||||
uint16_t net_id = NETWORK_ADDR_BC(list[0]); // BC address of source of RREQ
|
||||
route_table_entry_t* rte = rt_lookup_route(net_id); // Should exist (preconfigured)
|
||||
if (rte == NULL) { |
||||
DEBUG("exit [%u]: rt_extract_routes\n", fk_thread->pid); |
||||
return; // else exit here
|
||||
} |
||||
|
||||
int i = 0; |
||||
while (i < length && list[i] != local_addr) i++; |
||||
if (i == length) { |
||||
DEBUG("exit [%u]: rt_extract_routes\n", fk_thread->pid); |
||||
return; |
||||
} |
||||
|
||||
int pos = i; |
||||
int leftNeighbour = -1; |
||||
int rightNeighbour = -1; |
||||
if (pos > 0) |
||||
{ |
||||
leftNeighbour = list[pos-1]; |
||||
} |
||||
if (pos+1 != length) |
||||
{ |
||||
rightNeighbour = list[pos+1]; |
||||
} |
||||
|
||||
i = 0; |
||||
while (i < length) |
||||
{ |
||||
uint16_t next = list[i]; |
||||
if (local_addr != next) |
||||
{ |
||||
int distance = pos - i; |
||||
int router = leftNeighbour; |
||||
if (distance < 0) { router = rightNeighbour; distance *= -1; } |
||||
rt_add_route(next, (uint16_t)router, (uint8_t)distance, rte->interface_id); |
||||
} |
||||
i++; |
||||
} |
||||
DEBUG("exit [%u]: rt_extract_routes\n", fk_thread->pid); |
||||
} |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
// Message queue management
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
/**
|
||||
* @brief Add a message to the message queue. |
||||
* |
||||
* @param msg The packet to add to the queue |
||||
* |
||||
* @return A pointer to a message queue entry or NULL if |
||||
* message queue is full. |
||||
*/ |
||||
static message_queue_entry_t* mq_add(net_message_t* msg) |
||||
{ |
||||
DEBUG("call [%u]: mq_add\n", fk_thread->pid); |
||||
|
||||
// Holds eventually first active RREQ to same destination
|
||||
message_queue_entry_t* pFirstFoundDup = NULL; |
||||
|
||||
// Find the first active RREQ to this destination
|
||||
int i; |
||||
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) |
||||
{ |
||||
if (message_queue[i].timestamp != 0 && message_queue[i].message.destination == msg->destination && |
||||
message_queue[i].retry_count != RREQ_NONE) |
||||
{ |
||||
DEBUG("%s FOUND Duplicated Request to %u.%u in route req queue\n",__FUNCTION__,(0xFF00&msg->destination)>>8,(0xFF&msg->destination)); |
||||
|
||||
// Save the first found entry to modify later if insertion was successful
|
||||
pFirstFoundDup = &message_queue[i]; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
// If RREQ for same destination found then reset values
|
||||
// even if the new message will get dropped later on because of
|
||||
// limited queue space. Route to this destination gets queried
|
||||
// again for sure so make new RREQ as soon as possible...
|
||||
if (pFirstFoundDup != NULL) { |
||||
pFirstFoundDup->retry_count = 0; |
||||
pFirstFoundDup->timestamp = 1; |
||||
mmr_stats.rreq_duplicated++; |
||||
} |
||||
|
||||
// Find free position to insert new message
|
||||
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) |
||||
{ |
||||
if (message_queue[i].timestamp == 0) |
||||
{ |
||||
// Free position found, add entry
|
||||
message_queue[i].message = *msg; |
||||
if (pFirstFoundDup != NULL) { |
||||
// There is already a RREQ for this destination, so don't generate a new one
|
||||
message_queue[i].retry_count = RREQ_NONE; |
||||
} else { |
||||
// Set initial RREQ retry counter to zero
|
||||
message_queue[i].retry_count = 0; |
||||
} |
||||
message_queue[i].timestamp = 1; |
||||
DEBUG("exit [%u]: mq_add\n", fk_thread->pid); |
||||
return &message_queue[i]; |
||||
} |
||||
} |
||||
|
||||
DEBUG("exit [%u]: mq_add\n", fk_thread->pid); |
||||
return NULL; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Count messages for given destination. |
||||
* |
||||
* @param dst Destination address |
||||
* |
||||
* @return The number of messages for the destination. |
||||
*/ |
||||
static int mq_msgs_for_destination(uint16_t dst) |
||||
{ |
||||
DEBUG("call [%u]: mq_msgs_for_destination\n", fk_thread->pid); |
||||
int i, dst_count = 0; |
||||
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) |
||||
{ |
||||
if (message_queue[i].timestamp != 0 && message_queue[i].message.destination == dst) |
||||
{ |
||||
dst_count++; |
||||
} |
||||
} |
||||
DEBUG("exit [%u]: mq_msgs_for_destination\n", fk_thread->pid); |
||||
return dst_count; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Remove all messages for given destination out of message queue. |
||||
* |
||||
* @param dst Destination address |
||||
*/ |
||||
static void mq_remove_msgs_for_destination(uint16_t dst) |
||||
{ |
||||
DEBUG("call [%u]: mq_remove_msgs_for_destination\n", fk_thread->pid); |
||||
int i; |
||||
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) |
||||
{ |
||||
if (message_queue[i].timestamp != 0 && message_queue[i].message.destination == dst) |
||||
{ |
||||
message_queue[i].timestamp = 0; |
||||
} |
||||
} |
||||
DEBUG("exit [%u]: mq_remove_msgs_for_destination\n", fk_thread->pid); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Send all queued messages for given destination. |
||||
* |
||||
* @param dst Destination address |
||||
*/ |
||||
static void mq_dequeue_and_send(uint16_t dst) |
||||
{ |
||||
int i; |
||||
DEBUG("call [%u]: mq_dequeue_and_send\n", fk_thread->pid); |
||||
|
||||
// Stop any pending RREQ-Timeout, it's possibly handled now
|
||||
rreq_to_active = false; |
||||
utimer_remove(&ut); |
||||
|
||||
// Prioritize packets for given destination, route entry should exist
|
||||
route_table_entry_t* rte = rt_lookup_route(dst); |
||||
if (rte != NULL) |
||||
{ |
||||
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) |
||||
{ |
||||
if (message_queue[i].timestamp != 0 && message_queue[i].message.destination == dst) |
||||
{ |
||||
bool res = net_enqueue_for_transmission(&message_queue[i].message, rte->interface_id, rte->gateway, true); |
||||
if (res) message_queue[i].timestamp = 0; |
||||
} |
||||
} |
||||
} |
||||
// Now all other packets
|
||||
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) |
||||
{ |
||||
if (message_queue[i].timestamp != 0 && message_queue[i].message.destination != dst) |
||||
{ |
||||
route_table_entry_t* rte = rt_lookup_route(message_queue[i].message.destination); |
||||
if (rte != NULL) |
||||
{ |
||||
bool res = net_enqueue_for_transmission(&message_queue[i].message, rte->interface_id, rte->gateway, true); |
||||
if (res) message_queue[i].timestamp = 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// This function was triggered either by RREP packet or RREQ-Timeout.
|
||||
// So update or set new RREQ-Timeout for other packets in queue.
|
||||
post_next_rreq_timeout(); |
||||
DEBUG("exit [%u]: mq_dequeue_and_send\n", fk_thread->pid); |
||||
} |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
// Initialization of MMR layer
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
void mmr_init(void) |
||||
{ |
||||
rt_init(); |
||||
memset(message_queue, 0, sizeof(message_queue_entry_t) * MESSAGE_QUEUE_SIZE); |
||||
rreq_timeout_process_pid = thread_create(2500, PRIORITY_MMREQ, CREATE_STACKTEST, |
||||
rreq_timeout_process, rreq_timeout_process_name); |
||||
} |
||||
|
||||
/*---------------------------------------------------------------------------*/ |
||||
// Send & receive functions
|
||||
/*---------------------------------------------------------------------------*/ |
||||
|
||||
/**
|
||||
* @brief Tests if the net message contains a RERR. |
||||
* |
||||
* @param msg The net message to test |
||||
* |
||||
* @return true if the net message contains a RERR; false otherwise. |
||||
*/ |
||||
static bool is_route_error(net_message_t* msg) |
||||
{ |
||||
if (msg->protocol == LAYER_2_PROTOCOL_MMR) |
||||
{ |
||||
// First byte in {RREQ, RREP, RERR} is always type
|
||||
if (msg->payload[0] == MMR_TYPE_RERR) return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Generates a route reply message. |
||||
* |
||||
* @param rreq_msg Corresponding route request message |
||||
*/ |
||||
static void generate_route_reply_message(mmr_rreq_message_t* rreq_msg) |
||||
{ |
||||
DEBUG("call [%u]: generate_route_reply_message\n", fk_thread->pid); |
||||
// Create RREP message
|
||||
mmr_rrep_message_t rrep_msg; |
||||
rrep_msg.type = MMR_TYPE_RREP; |
||||
rrep_msg.length = rreq_msg->length; |
||||
rrep_msg.destination = rreq_msg->source; |
||||
rrep_msg.source = rreq_msg->destination; |
||||
memcpy(rrep_msg.address, rreq_msg->address, rreq_msg->length * sizeof(uint16_t)); |
||||
|
||||
// Create MMR message containing the RREP message
|
||||
net_message_t net_msg; |
||||
net_msg.protocol = LAYER_2_PROTOCOL_MMR; |
||||
net_msg.flags_tos = PRIORITY_ALARM; |
||||
net_msg.seq_clr_id = 0; |
||||
net_msg.ttl = TTL_THRESHOLD; |
||||
net_msg.source = rrep_msg.source; |
||||
net_msg.destination = rrep_msg.destination; |
||||
memcpy(net_msg.payload, (void*)&rrep_msg, sizeof(mmr_rrep_message_t)); |
||||
|
||||
// Source address must exist in route table to find correct
|
||||
// interface id and next hop (should be created by RREQ)
|
||||
route_table_entry_t* rte = rt_lookup_route(net_msg.destination); |
||||
if (rte != NULL) |
||||
{ |
||||
// Send message to next hop
|
||||
mmr_stats.rrep_originated++; |
||||
net_enqueue_for_transmission(&net_msg, rte->interface_id, rte->gateway, true); |
||||
} |
||||
DEBUG("exit [%u]: generate_route_reply_message\n", fk_thread->pid); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Generates a route error message. |
||||
* |
||||
* @param dst Destination address of RERR packet |
||||
* @param gateway Next hop network address of RERR packet |
||||
* @param intf Interface id of RERR packet |
||||
* @param type Error type of RERR packet |
||||
* @param type_data Type specific data of RERR packet |
||||
*/ |
||||
static void generate_route_error_message(uint16_t dst, uint16_t gateway, int intf, uint8_t type, uint16_t type_data) |
||||
{ |
||||
DEBUG("call [%u]: generate_route_error_message\n", fk_thread->pid); |
||||
// Define RERR message
|
||||
mmr_rerr_message_t rerr_msg; |
||||
rerr_msg.type = MMR_TYPE_RERR; |
||||
rerr_msg.error_type = type; |
||||
rerr_msg.type_specific_info = type_data; |
||||
|
||||
// Wrap RERR message in net message
|
||||
net_message_t net_msg; |
||||
net_msg.protocol = LAYER_2_PROTOCOL_MMR; |
||||
net_msg.flags_tos = PRIORITY_DATA; |
||||
net_msg.seq_clr_id = 0; |
||||
net_msg.ttl = TTL_THRESHOLD; |
||||
net_msg.source = net_get_address_in_subnet(dst); |
||||
net_msg.destination = dst; |
||||
memcpy(net_msg.payload, (void*)&rerr_msg, sizeof(mmr_rerr_message_t)); |
||||
|
||||
// Send message to next hop
|
||||
mmr_stats.rerr_originated++; |
||||
net_enqueue_for_transmission(&net_msg, intf, gateway, true); |
||||
DEBUG("exit [%u]: generate_route_error_message\n", fk_thread->pid); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Receive a route request message. |
||||
* |
||||
* @param msg The route request packet |
||||
* @param packet_info Additional packet information |
||||
*/ |
||||
static void receive_route_request_message(mmr_rreq_message_t* msg, packet_info_t* packet_info) |
||||
{ |
||||
DEBUG("call [%u]: receive_route_request_message\n", fk_thread->pid); |
||||
uint16_t my_addr = net_get_address_in_subnet(msg->source); |
||||
#if (MMR_INFO_LEVEL >= LEVEL_WARN) |
||||
if (my_addr == 0) |
||||
{ |
||||
puts("MMR [WARN]: received RREQ with unknown network part of source address"); |
||||
puts("MMR [WARN]: => can't find own net address in sub net!"); |
||||
} |
||||
#endif |
||||
// If address list of RREQ message has enough space
|
||||
if (msg->length < ADDRESS_LIST_SIZE) |
||||
{ |
||||
// append our node id to list
|
||||
msg->address[msg->length++] = my_addr; |
||||
// add routes with overhearing
|
||||
rt_extract_routes(my_addr, msg->length, msg->address); |
||||
} |
||||
// Distance between sender and receiver is too long, discard packet
|
||||
else |
||||
{ |
||||
// Drop RREQ packet => set TTL to zero
|
||||
*packet_info->ttl_ptr = 0; |
||||
DEBUG("exit [%u]: receive_route_request_message\n", fk_thread->pid); |
||||
return; |
||||
} |
||||
|
||||
// If RREQ message was send to us, then send RREP message
|
||||
if (msg->destination == my_addr) |
||||
{ |
||||
// Don't forward RREQ packet any further => set TTL to zero
|
||||
*packet_info->ttl_ptr = 0; |
||||
generate_route_reply_message(msg); |
||||
} |
||||
DEBUG("exit [%u]: receive_route_request_message\n", fk_thread->pid); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Receive a route reply message. |
||||
* |
||||
* @param msg The route reply packet |
||||
* @param packet_info Additional packet information |
||||
*/ |
||||
static void receive_route_reply_message(mmr_rrep_message_t* msg, packet_info_t* packet_info) |
||||
{ |
||||
DEBUG("call [%u]: receive_route_reply_message\n", fk_thread->pid); |
||||
// RREP received: Send out queued packets for which routes are now known
|
||||
mq_dequeue_and_send(msg->source); |
||||
DEBUG("exit [%u]: receive_route_reply_message\n", fk_thread->pid); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Receive a route error message. |
||||
* |
||||
* @param msg The route error packet |
||||
* @param packet_info Additional packet information |
||||
*/ |
||||
static void receive_route_error_message(mmr_rerr_message_t* msg, packet_info_t* packet_info) |
||||
{ |
||||
DEBUG("call [%u]: receive_route_error_message\n", fk_thread->pid); |
||||
switch (msg->error_type) |
||||
{ |
||||
case RERR_NODE_UNREACHABLE: |
||||
rt_remove_route(msg->type_specific_info); |
||||
break; |
||||
default: |
||||
#if (MMR_INFO_LEVEL >= LEVEL_INFO) |
||||
puts("MMR [INFO]: RERR error type is unknown"); |
||||
#endif |
||||
break; |
||||
} |
||||
DEBUG("exit [%u]: receive_route_error_message\n", fk_thread->pid); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Computes the RREQ timeout period, given a |
||||
* TTL and destination address value. |
||||
* |
||||