diff --git a/core/include/kernel_intern.h b/core/include/kernel_intern.h index 7b5bd12c1..ca50b55e3 100644 --- a/core/include/kernel_intern.h +++ b/core/include/kernel_intern.h @@ -17,10 +17,10 @@ #define KERNEL_INTERN_H_ void kernel_init(void); -void board_init_drivers(); +void board_init_drivers(void); char *thread_stack_init(void *task_func, void *stack_start); void sched_task_exit(void); -void thread_print_stack (); +void thread_print_stack (void); int thread_measure_stack_usage(char* stack); /** @} */ diff --git a/core/include/sched.h b/core/include/sched.h index 9f9712249..5f3c3ce15 100644 --- a/core/include/sched.h +++ b/core/include/sched.h @@ -21,8 +21,8 @@ #define SCHED_PRIO_LEVELS 16 #endif -void sched_init(); -void sched_run(); +void sched_init(void); +void sched_run(void); void sched_set_status(tcb_t *process, unsigned int status); void sched_switch(uint16_t current_prio, uint16_t other_prio, int in_isr); diff --git a/core/include/thread.h b/core/include/thread.h index 11c620c3d..31fb4e80a 100644 --- a/core/include/thread.h +++ b/core/include/thread.h @@ -46,7 +46,7 @@ unsigned int thread_getstatus(int pid); /** * @brief Puts the current thread into sleep mode. Has to be woken up externally. */ -void thread_sleep(); +void thread_sleep(void); /** * @brief Wakes up a sleeping thread. @@ -60,13 +60,13 @@ int thread_wakeup(int pid); * @brief Returns the process ID of the currently running thread. * @return Obviously you are not a golfer. */ -int thread_getpid(); +int thread_getpid(void); /** * @brief Returns the process ID of the thread running before the current one. * @return Obviously you are not a golfer. */ -int thread_getlastpid(); +int thread_getlastpid(void); /** * @brief Measures the stack usage of a stack. diff --git a/core/makefile b/core/makefile new file mode 100644 index 000000000..a3e669793 --- /dev/null +++ b/core/makefile @@ -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 diff --git a/core/mutex.c b/core/mutex.c index 9575fd118..b4293a629 100644 --- a/core/mutex.c +++ b/core/mutex.c @@ -40,7 +40,7 @@ int mutex_trylock(struct mutex_t* mutex) { return (atomic_set_return(&mutex->val, thread_pid ) == 0); } -int prio() { +int prio(void) { return active_thread->priority; } diff --git a/core/oneway_malloc.c b/core/oneway_malloc.c index d10e23b96..3b73dc6c3 100644 --- a/core/oneway_malloc.c +++ b/core/oneway_malloc.c @@ -23,12 +23,12 @@ #define ENABLE_DEBUG #include -extern void *sbrk(int incr); +//extern void *sbrk(int incr); void *_malloc(size_t size) { void* ptr = sbrk(size); - DEBUG("_malloc(): allocating block of size %u at 0x%X.\n", size, (unsigned int)ptr); + DEBUG("_malloc(): allocating block of size %u at 0x%X.\n", (unsigned int) size, (unsigned int)ptr); if (ptr != (void*)-1) { return ptr; diff --git a/cpu/arm_common/VIC.c b/cpu/arm_common/VIC.c index f6cd6a3f5..7dd0364ee 100644 --- a/cpu/arm_common/VIC.c +++ b/cpu/arm_common/VIC.c @@ -17,7 +17,6 @@ along with Micro-Mesh; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "board.h" #include "VIC.h" #include diff --git a/cpu/arm_common/include/arm_cpu.h b/cpu/arm_common/include/arm_cpu.h index 6272119a6..91944ab81 100644 --- a/cpu/arm_common/include/arm_cpu.h +++ b/cpu/arm_common/include/arm_cpu.h @@ -8,10 +8,10 @@ #define NEW_TASK_CPSR 0x1F #define WORDSIZE 32 -extern void dINT(); -extern void eINT(); +extern void dINT(void); +extern void eINT(void); -void thread_yield(); +void thread_yield(void); uint32_t get_system_speed(void); void cpu_clock_scale(uint32_t source, uint32_t target, uint32_t* prescale); diff --git a/cpu/arm_common/makefile b/cpu/arm_common/makefile new file mode 100644 index 000000000..0ac2b1fe1 --- /dev/null +++ b/cpu/arm_common/makefile @@ -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 + + + diff --git a/cpu/cc430/makefile b/cpu/cc430/makefile new file mode 100644 index 000000000..734a4056a --- /dev/null +++ b/cpu/cc430/makefile @@ -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 ; + diff --git a/cpu/lpc214x/makefile b/cpu/lpc214x/makefile new file mode 100644 index 000000000..fd9c47f8e --- /dev/null +++ b/cpu/lpc214x/makefile @@ -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 + + + + diff --git a/cpu/lpc2387/lpc2387-lpm.c b/cpu/lpc2387/lpc2387-lpm.c index ff83433e3..e14cd9a30 100644 --- a/cpu/lpc2387/lpc2387-lpm.c +++ b/cpu/lpc2387/lpc2387-lpm.c @@ -43,7 +43,6 @@ and the mailinglist (subscription via web site) #include #include -#include "board.h" #include "lpc23xx.h" #include "lpc2387.h" #include "lpm.h" diff --git a/cpu/lpc2387/makefile b/cpu/lpc2387/makefile new file mode 100644 index 000000000..9e4733671 --- /dev/null +++ b/cpu/lpc2387/makefile @@ -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 ; + diff --git a/cpu/makefile b/cpu/makefile new file mode 100644 index 000000000..3734b6393 --- /dev/null +++ b/cpu/makefile @@ -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 + + + diff --git a/cpu/msp430-common/makefile b/cpu/msp430-common/makefile new file mode 100644 index 000000000..734a4056a --- /dev/null +++ b/cpu/msp430-common/makefile @@ -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 ; + diff --git a/drivers/cc110x/makefile b/drivers/cc110x/makefile new file mode 100644 index 000000000..b2e804282 --- /dev/null +++ b/drivers/cc110x/makefile @@ -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 + + diff --git a/drivers/cc110x_ng/makefile b/drivers/cc110x_ng/makefile new file mode 100644 index 000000000..f8a7cfa78 --- /dev/null +++ b/drivers/cc110x_ng/makefile @@ -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 + + diff --git a/drivers/include/ltc4150.h b/drivers/include/ltc4150.h index fdc08573a..e94e9d005 100644 --- a/drivers/include/ltc4150.h +++ b/drivers/include/ltc4150.h @@ -3,15 +3,15 @@ #include -void ltc4150_init(); -void ltc4150_start(); -void ltc4150_stop(); +void ltc4150_init(void); +void ltc4150_start(void); +void ltc4150_stop(void); -double ltc4150_get_current_mA(); -double ltc4150_get_total_mAh(); +double ltc4150_get_current_mA(void); +double ltc4150_get_total_mAh(void); double ltc4150_get_total_Joule(void); -double ltc4150_get_avg_mA(); -int ltc4150_get_interval(); +double ltc4150_get_avg_mA(void); +int ltc4150_get_interval(void); long ltc4150_get_intcount(void); #endif /* __LTC4150_H */ diff --git a/drivers/include/ltc4150_arch.h b/drivers/include/ltc4150_arch.h index 51fc9478a..51c76ca59 100644 --- a/drivers/include/ltc4150_arch.h +++ b/drivers/include/ltc4150_arch.h @@ -52,7 +52,7 @@ void ltc4150_disable_int(void); void ltc4150_enable_int(void); void ltc4150_sync_blocking(void); void ltc4150_arch_init(void); -void ltc4150_interrupt(); +void ltc4150_interrupt(void); /** @} */ #endif /* __LTC4150_ARCH_H */ diff --git a/drivers/ltc4150.c b/drivers/ltc4150/ltc4150.c similarity index 100% rename from drivers/ltc4150.c rename to drivers/ltc4150/ltc4150.c diff --git a/drivers/ltc4150/makefile b/drivers/ltc4150/makefile new file mode 100644 index 000000000..56eb0df1f --- /dev/null +++ b/drivers/ltc4150/makefile @@ -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 + + diff --git a/drivers/makefile b/drivers/makefile new file mode 100644 index 000000000..18ec45998 --- /dev/null +++ b/drivers/makefile @@ -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 ; + + + + diff --git a/drivers/sht11/makefile b/drivers/sht11/makefile new file mode 100644 index 000000000..ac4e9acf9 --- /dev/null +++ b/drivers/sht11/makefile @@ -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 + + diff --git a/drivers/sht11.c b/drivers/sht11/sht11.c similarity index 100% rename from drivers/sht11.c rename to drivers/sht11/sht11.c diff --git a/makefile b/makefile new file mode 100644 index 000000000..88fd8667a --- /dev/null +++ b/makefile @@ -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 ; + + diff --git a/makefile.base b/makefile.base new file mode 100644 index 000000000..9de16b514 --- /dev/null +++ b/makefile.base @@ -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) + diff --git a/makefile.modules b/makefile.modules new file mode 100644 index 000000000..a3c758412 --- /dev/null +++ b/makefile.modules @@ -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 diff --git a/sys/include/ping.h b/sys/include/ping.h index f5ef40e1c..be73f8107 100644 --- a/sys/include/ping.h +++ b/sys/include/ping.h @@ -1,13 +1,13 @@ #include "radio/radio.h" -void init_payload(); +void init_payload(void); void ping_init(protocol_t protocol, uint8_t channr, radio_address_t addr); void ping(radio_address_t addr, uint8_t channr); -void calc_rtt(); -void print_success(); -void print_failed(); -void gpio_n_timer_init(); -void adjust_timer(); +void calc_rtt(void); +void print_success(void); +void print_failed(void); +void gpio_n_timer_init(void); +void adjust_timer(void); static void ping_handler(void *payload, int payload_size, packet_info_t *packet_info); static void pong_handler(void *payload, int payload_size, diff --git a/sys/include/swtimer.h b/sys/include/swtimer.h index b1962d524..fc17204ba 100644 --- a/sys/include/swtimer.h +++ b/sys/include/swtimer.h @@ -65,13 +65,13 @@ typedef struct swtimer_t { * @brief Current system time * @return Time in ticks since system boot */ -swtime_t swtimer_now(); +swtime_t swtimer_now(void); /** * @brief Initializes swtimer * @return always 0 */ -int swtimer_init(); +int swtimer_init(void); /** * @brief set swtimer interval and activate diff --git a/sys/include/vtimer.h b/sys/include/vtimer.h index 2a5d7a0d9..def966601 100644 --- a/sys/include/vtimer.h +++ b/sys/include/vtimer.h @@ -43,14 +43,14 @@ typedef struct vtimer_t { * @brief Current system time * @return Time as timex_t since system boot */ -timex_t vtimer_now(); +timex_t vtimer_now(void); /** * @brief Initializes the vtimer subsystem. To be called once at system initialization. Will be initialized by auto_init. * * @return always 0 */ -int vtimer_init(); +int vtimer_init(void); /** * @brief will cause the calling thread to be suspended from excecution until the number of microseconds has elapsed diff --git a/sys/lib/makefile b/sys/lib/makefile new file mode 100644 index 000000000..982135d36 --- /dev/null +++ b/sys/lib/makefile @@ -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 + + diff --git a/sys/logd/logd.c b/sys/logd/logd.c new file mode 100644 index 000000000..2dcfa1196 --- /dev/null +++ b/sys/logd/logd.c @@ -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 + * @version $Revision: 3854 $ + * + * @note $Id: logd.c 3854 2011-12-06 15:27:01Z hwill $ + */ + +#include +#include +#include +#include +// 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); +} diff --git a/sys/logd/makefile b/sys/logd/makefile new file mode 100644 index 000000000..92bc22a69 --- /dev/null +++ b/sys/logd/makefile @@ -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 + + diff --git a/sys/makefile b/sys/makefile new file mode 100644 index 000000000..88fc7b663 --- /dev/null +++ b/sys/makefile @@ -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 ; + + + diff --git a/sys/net/mm/Jamfile b/sys/net/mm/Jamfile new file mode 100644 index 000000000..fd3bf49ba --- /dev/null +++ b/sys/net/mm/Jamfile @@ -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 ; + diff --git a/sys/net/mm/makefile b/sys/net/mm/makefile new file mode 100644 index 000000000..616321f4c --- /dev/null +++ b/sys/net/mm/makefile @@ -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 + diff --git a/sys/net/mm/mmr.c b/sys/net/mm/mmr.c new file mode 100644 index 000000000..a1bf646b5 --- /dev/null +++ b/sys/net/mm/mmr.c @@ -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 + * @version $Revision: 3854 $ + * + * @note $Id: mmr.c 3854 2011-12-06 15:27:01Z hwill $ + */ + +#include "configure.h" +#include "mmr.h" +#include +#include +#include + +#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. + * + * @param ttl Time to live + * @param dst Network destination address + * + * @return RREQ timeout period in seconds + */ +static int compute_rreq_timeout(int ttl, uint16_t dst) +{ + int t_hop = net_get_interface_transmission_duration(dst); + if (t_hop == -1) { + t_hop = RREQ_TIMEOUT_PER_TTL * ttl; + } else { + t_hop = (t_hop * ttl + 999) / 1000; + } + return RREQ_TIMEOUT_BASE + 2 * t_hop; +} + +/** + * @brief Broadcast a RREQ message. + * + * A single route request can repeatedly broadcast RREQ messages, + * with increasing TTL value, until a route has been found. + * + * @param mq_entry Pointer to a message queue entry (the packet + * for which to find the route) + */ +static void rreq_broadcast(message_queue_entry_t* mq_entry) +{ + DEBUG("call [%u]: rreq_broadcast\n", fk_thread->pid); + if(mq_entry->retry_count == RREQ_NONE) + { + DEBUG("call [%u]: rreq duplicated do not send\n", fk_thread->pid); + return; + } + // Create RREQ message + mmr_rreq_message_t rreq_msg; + rreq_msg.type = MMR_TYPE_RREQ; + rreq_msg.length = 1; + rreq_msg.destination = mq_entry->message.destination; + rreq_msg.source = mq_entry->message.source; + rreq_msg.address[0] = mq_entry->message.source; + + // Wrap RREQ 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 = mq_entry->retry_count == 0 ? TTL_START : TTL_THRESHOLD; + net_msg.source = rreq_msg.source; + net_msg.destination = NETWORK_ADDR_BC(rreq_msg.destination); + memcpy(net_msg.payload, (void*)&rreq_msg, sizeof(mmr_rreq_message_t)); + + // Broadcast the net message + mq_entry->retry_count++; + mq_entry->timestamp = rtc_now(); + // Find the broadcast route table entry + route_table_entry_t* rte = rt_lookup_route(net_msg.destination); + if (rte != NULL) + { + // Next hop address is broadcast address of lower layer + net_enqueue_for_transmission(&net_msg, rte->interface_id, rte->gateway, true); + } + DEBUG("exit [%u]: rreq_broadcast\n", fk_thread->pid); +} + +/** + * @brief Find next RREQ to time out. Post event immediately or + * with utimer. + */ +static void post_next_rreq_timeout(void) +{ + DEBUG("call [%u]: post_next_rreq_timeout\n", fk_thread->pid); + int i, j = -1; + uint32_t now, next = 0xffffffff; + for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) + { + if (message_queue[i].timestamp != 0 && message_queue[i].retry_count != RREQ_NONE) + { + int ttl = message_queue[i].retry_count == 1 ? TTL_START : TTL_THRESHOLD; + int to = compute_rreq_timeout(ttl, message_queue[i].message.destination); + if (message_queue[i].timestamp + to < next) + { + next = message_queue[i].timestamp + to; + j = i; + } + } + } + if (j == -1) { + DEBUG("exit [%u]: post_next_rreq_timeout\n", fk_thread->pid); + return; + } + // Stop any utimer + rreq_to_active = false; + utimer_remove(&ut); + // If current time greater than RREQ timeout value + now = rtc_now(); + if (now >= next) + { + // Schedule RREQ-Timeout immediately + msg m; + m.type = MSG_TIMER; + m.content.ptr = (char*)&message_queue[j]; + rreq_to_active = true; + if (msg_send(&m, rreq_timeout_process_pid, false) != 1) { + // Message could not be send (receiver not waiting), schedule timer with minimum delay +#if (MMR_INFO_LEVEL >= LEVEL_WARN) + puts("MMR [WARN]: Immediate schedule of RREQ-Timeout failed, process not waiting!"); +#endif + utimer_set_wpid(&ut, 1, rreq_timeout_process_pid, &message_queue[j]); + } + } + else + { + // Set new utimer with time difference + rreq_to_active = true; + utimer_set_wpid(&ut, next - now, rreq_timeout_process_pid, &message_queue[j]); + } + DEBUG("exit [%u]: post_next_rreq_timeout\n", fk_thread->pid); +} + +/** + * This event is called periodically after a route request is originated, + * until a route has been found. + * + * Each time it is called, it rebroadcasts the route request message with a + * new rreq id and incremented TTL. + */ +static void rreq_timeout(message_queue_entry_t* mqe) +{ + DEBUG("call [%u]: rreq_timeout\n", fk_thread->pid); + // Test if valid entry passed + if (mqe->timestamp == 0) + { +#if (MMR_INFO_LEVEL >= LEVEL_WARN) + puts("MMR [WARN]: invalid message queue entry for RREQ-Timeout"); +#endif + goto post_next_to; + } + // See if route to destination was found + route_table_entry_t* rte = rt_lookup_route(mqe->message.destination); + // If found and no messages in queue for destination: return (queued + // packets are send on reception of RREP); If found but messages in + // queue: trigger send immediately here! + if (rte != NULL) + { + int msg_count = mq_msgs_for_destination(mqe->message.destination); + if (msg_count > 0) + { + mq_dequeue_and_send(mqe->message.destination); + DEBUG("exit [%u]: rreq_timeout\n", fk_thread->pid); + return; + } + else + { + // Added just for security but this case should never occur +#if (MMR_INFO_LEVEL >= LEVEL_WARN) + puts("MMR [WARN]: RREQ-Timeout occurred, route is available but no messages for destination"); +#endif + // Anyway: jump to update next RREQ-Timeout + goto post_next_to; + } + } + // Otherwise send new RREQ if below threshold (means also retry count != RREQ_NONE) + if (mqe->retry_count < RREQ_THRESHOLD) + { + // Broadcast new RREQ message (with incremented TTL) + rreq_broadcast(mqe); + } + else + { + // Remove all messages for this destination + mmr_stats.messages_no_route_found++; + mq_remove_msgs_for_destination(mqe->message.destination); + } + // Anyway: update or set next RREQ-Timeout + post_next_to: + post_next_rreq_timeout(); + DEBUG("exit [%u]: rreq_timeout\n", fk_thread->pid); +} + +static void rreq_timeout_process(void) +{ + msg m; + do + { + msg_receive(&m); + if (m.type == MSG_TIMER && rreq_to_active) + { + rreq_to_active = false; + rreq_timeout((message_queue_entry_t*)m.content.ptr); + } + } while (m.type != MSG_EXIT); +} + +void mmr_peek(net_message_t* message, packet_info_t* packet_info) +{ + DEBUG("call [%u]: mmr_peek\n", fk_thread->pid); + // Only look at micro mesh routing messages + if (message->protocol == LAYER_2_PROTOCOL_MMR) + { + uint8_t type = message->payload[0]; + uint16_t my_addr = net_get_address_in_subnet(message->source); + if (type == MMR_TYPE_RREP) + { + // Add routes to route table + mmr_rrep_message_t* rrep_msg = (mmr_rrep_message_t*)message->payload; +#if (MMR_INFO_LEVEL >= LEVEL_WARN) + if (my_addr == 0) + { + puts("MMR [WARN]: received RREP with unknown network part of source address"); + puts("MMR [WARN]: => can't find own net address in sub net!"); + } +#endif + rt_extract_routes(my_addr, rrep_msg->length, rrep_msg->address); + } + else if (type == MMR_TYPE_RERR) + { +#if (MMR_INFO_LEVEL >= LEVEL_WARN) + if (my_addr == 0) + { + puts("MMR [WARN]: received RERR with unknown network part of source address"); + puts("MMR [WARN]: => can't find own net address in sub net!"); + } +#endif + // If not destination of RERR, then remove route to unavailable node in RERR packet + if (message->destination != my_addr) + { + mmr_rerr_message_t* rerr_msg = (mmr_rerr_message_t*)message->payload; + if (rerr_msg->error_type == RERR_NODE_UNREACHABLE) + { + rt_remove_route(rerr_msg->type_specific_info); + } + } + } + } + DEBUG("exit [%u]: mmr_peek\n", fk_thread->pid); +} + +bool mmr_send(net_message_t* message) +{ + DEBUG("call [%u]: mmr_send\n", fk_thread->pid); + bool enqueue = true; + if (message->destination == net_get_address_in_subnet(message->destination)) + { +#if (MMR_INFO_LEVEL >= LEVEL_WARN) + puts("MMR [WARN]: message is already at destination, why is routing called?"); +#endif + DEBUG("exit [%u]: mmr_send\n", fk_thread->pid); + return false; + } + if (NETWORK_ADDR_NET(message->destination) == 0) + { +#if (MMR_INFO_LEVEL >= LEVEL_WARN) + puts("MMR [WARN]: NET part of address cannot be 0!"); +#endif + DEBUG("exit [%u]: mmr_send\n", fk_thread->pid); + return false; + } + if (NETWORK_ADDR_HOST(message->destination) == 0) + { +#if (MMR_INFO_LEVEL >= LEVEL_INFO) + puts("MMR [INFO]: broadcast destination, why is routing called? A route entry should exist!"); +#endif + enqueue = false; + } + + // Look up next hop address for this destination in routing table + route_table_entry_t* rte = rt_lookup_route(message->destination); + + // If next hop address found in routing table, forward message + if (rte != NULL) + { + DEBUG("exit [%u]: mmr_send\n", fk_thread->pid); + return net_enqueue_for_transmission(message, rte->interface_id, rte->gateway, true); + } + // Otherwise, save message in queue; broadcast RREQ message + else + { + if (!enqueue) { DEBUG("exit [%u]: mmr_send\n", fk_thread->pid); return false; } // Don't enqueue broadcast destinations + message_queue_entry_t* mqe = mq_add(message); + if (mqe != NULL) + { + rreq_broadcast(mqe); + post_next_rreq_timeout(); + mmr_stats.rreq_originated++; + DEBUG("exit [%u]: mmr_send\n", fk_thread->pid); + return true; + } + } + DEBUG("exit [%u]: mmr_send\n", fk_thread->pid); + return false; +} + +void mmr_packet_dropped(net_message_t* message, uint16_t next_hop, int error) +{ + DEBUG("call [%u]: mmr_packet_dropped\n", fk_thread->pid); + if (error == ROUTE_ERROR_BROKEN_ROUTE) + { + // Local failure detected - remove all routes through broken link + rt_remove_gateway_routes(next_hop); + mmr_stats.messages_broken_link_on_forward++; + } + else if (error == ROUTE_ERROR_MISSING_ROUTE) + { + mmr_stats.messages_no_route_avail_on_forward++; + } + + // If source != net_addr, send RERR to source of message + if (message->source != net_get_address_in_subnet(message->source)) + { + // Do not generate RERR if it is already a RERR message + if (is_route_error(message)) { DEBUG("exit [%u]: mmr_packet_dropped\n", fk_thread->pid); return; } + // Find next hop to source + route_table_entry_t* rte = rt_lookup_route(message->source); + if (rte != NULL) + { + generate_route_error_message(message->source, rte->gateway, + rte->interface_id, RERR_NODE_UNREACHABLE, message->destination); + } +#if (MMR_INFO_LEVEL >= LEVEL_WARN) + else + { + printf("MMR [WARN]: cannot send RERR to source #%u, no route found!\n", message->source); + } +#endif + } + DEBUG("exit [%u]: mmr_packet_dropped\n", fk_thread->pid); +} + +void mmr_receive(void* msg, int msg_size, packet_info_t* packet_info) +{ + DEBUG("call [%u]: mmr_receive\n", fk_thread->pid); + uint8_t* p = (uint8_t*) msg; + uint8_t type = p[0]; + if (type == MMR_TYPE_RREQ) + { + receive_route_request_message((mmr_rreq_message_t*)msg, packet_info); + mmr_stats.rreq_received++; + } + else if (type == MMR_TYPE_RREP) + { + receive_route_reply_message((mmr_rrep_message_t*)msg, packet_info); + mmr_stats.rrep_received++; + } + else if (type == MMR_TYPE_RERR) + { + receive_route_error_message((mmr_rerr_message_t*)msg, packet_info); + mmr_stats.rerr_received++; + } +#if (MMR_INFO_LEVEL >= LEVEL_INFO) + else + { + printf("MMR [INFO]: can't handle message of type %u\n", type); + } +#endif + DEBUG("exit [%u]: mmr_receive\n", fk_thread->pid); +} + +void mmr_print_stats(void) +{ + printf("ROUTING LAYER STATS\r\n"); + printf("-------------------\r\n"); + printf("Route requests originated: %lu\r\n", mmr_stats.rreq_originated); + printf("Route requests duplicated: %lu\r\n", mmr_stats.rreq_duplicated); + printf("Route replies originated: %lu\r\n", mmr_stats.rrep_originated); + printf("Route errors originated: %lu\r\n", mmr_stats.rerr_originated); + printf("Route requests received: %lu\r\n", mmr_stats.rreq_received); + printf("Route replies received: %lu\r\n", mmr_stats.rrep_received); + printf("Route errors received: %lu\r\n", mmr_stats.rerr_received); + printf("\r\n"); + printf("#Messages with no route found: %lu\r\n", mmr_stats.messages_no_route_found); + printf("#Messages with broken link on forward: %lu\r\n", mmr_stats.messages_broken_link_on_forward); + printf("#Messages with no route available on forward: %lu\r\n", mmr_stats.messages_no_route_avail_on_forward); + printf("\r\n"); +} diff --git a/sys/net/mm/mmr.h b/sys/net/mm/mmr.h new file mode 100644 index 000000000..faff3572c --- /dev/null +++ b/sys/net/mm/mmr.h @@ -0,0 +1,174 @@ +/****************************************************************************** +Copyright 2008, 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 +*******************************************************************************/ + +#ifndef MMR_H_ +#define MMR_H_ + +/** + * @file + * @internal + * @brief Micro Mesh Routing + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Thomas Hillebrandt + * @version $Revision: 3854 $ + * + * @note $Id: mmr.h 3854 2011-12-06 15:27:01Z hwill $ + */ + +#include "net-types.h" + +#define MMR_TYPE_RREQ (1) +#define MMR_TYPE_RREP (2) +#define MMR_TYPE_RERR (3) + + #define ADDRESS_LIST_SIZE (21) + +#define RERR_NODE_UNREACHABLE (1) + +/** + * Represents a Route Request (RREQ) message. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Destination | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source | Address[1..n] | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct __attribute__ ((packed)) mmr_rreq_message_t +{ + uint8_t type; ///< Must be first byte in struct for type detection + uint8_t length; + uint16_t destination; + uint16_t source; + uint16_t address[ADDRESS_LIST_SIZE]; +} mmr_rreq_message_t; + +/** + * Represents a Route Reply (RREP) message. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Destination | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source | Address[1..n] | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct __attribute__ ((packed)) mmr_rrep_message_t +{ + uint8_t type; ///< Must be first byte in struct for type detection + uint8_t length; + uint16_t destination; + uint16_t source; + uint16_t address[ADDRESS_LIST_SIZE]; +} mmr_rrep_message_t; + +/** + * Represents a Route Error (RERR) message. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Error Type | Type-Specific Information | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Valid Error Types are: + * + * 1 = NODE_UNREACHABLE + * + * Node Unreachable Type-Specific Information: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Unreachable Node Address | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +typedef struct __attribute__ ((packed)) mmr_rerr_message_t +{ + uint8_t type; ///< Must be first byte in struct for type detection + uint8_t error_type; + uint16_t type_specific_info; +} mmr_rerr_message_t; + +/** + * @brief Initialize MMR layer. + */ +void mmr_init(void); + +/** + * Called by the network layer for every incoming packet. A routing + * implementation may wish to look at these packets for informational + * purposes, but should not change their contents. + * + * @param message incoming packet + * @param packet_info Additional packet information + */ +void mmr_peek(net_message_t* message, packet_info_t* packet_info); + +/** + * Called by the network layer to request transmission of a packet that + * requires routing. It is the responsibility of the routing layer to provide + * a best-effort transmission of this packet to an appropriate next hop by + * calling the networks layer sending routines once this routing information + * becomes available. + * + * @param message outgoing packet + * + * @return true if packet was successfully stored for transmission; false otherwise + * (e.g. message queue full). + */ +bool mmr_send(net_message_t* message); + +/** + * Called by the network layer which forwards notifications of dropped packets + * from the link layer. Not all MAC implementations support this feature! + * + * @param message dropped network packet + * @param next_hop next hop network address of dropped packet (can be undefined) + * @param error Error type which informs about reason + */ +void mmr_packet_dropped(net_message_t* message, uint16_t next_hop, int error); + +/** + * @brief Receive a message from network layer. + * + * @param msg message received + * @param msg_size Size of received message + * @param packet_info Additional packet information + */ +void mmr_receive(void* msg, int msg_size, packet_info_t* packet_info); + +/** + * @brief Print routing layer statistics. + */ +void mmr_print_stats(void); + +#endif /* MMR_H_ */ diff --git a/sys/net/mm/mmstack.c b/sys/net/mm/mmstack.c new file mode 100644 index 000000000..56fdb4d3d --- /dev/null +++ b/sys/net/mm/mmstack.c @@ -0,0 +1,797 @@ +/****************************************************************************** +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 +*******************************************************************************/ + +#include "configure.h" +#include "mmstack.h" +#include +#include +#include + +#include "utimer.h" +#include "kernel.h" +#include "thread.h" +#include "msg.h" + +#include "net.h" +#include "mmr.h" +#include "trans.h" +#include "clock.h" +#include "cmdengine.h" + +/** + * @file + * @brief + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Thomas Hillebrandt + * @version $Revision: 3854 $ + * + * @note $Id: mmstack.c 3854 2011-12-06 15:27:01Z hwill $ + */ + +/*---------------------------------------------------------------------------*/ +// Data structures for build in ping +/*---------------------------------------------------------------------------*/ + +#define MMS_PING_PACKETS (4) ///< Default number of packets in a ping +#define MMS_PING_ECHO_REQUEST (8) ///< Ping type: echo request +#define MMS_PING_ECHO_REPLY (0) ///< Ping type: echo reply + +/** + * Represents a ping message. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Identifier | SeqNum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Timestamp | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct __attribute__ ((packed)) mms_ping_message_t +{ + uint8_t type; ///< Type of ping message (request or reply) + uint8_t identifier; ///< Unique identifier for ping process + uint16_t seq_num; ///< Sequence number (increasing number within that process) + uint32_t timestamp; ///< Timestamp of request message +} mms_ping_message_t; + +/** + * @brief Send ping echo request to destination address. + * + * @param destination The destination address. + * @param seq Sequence number of ping message. + * @param prio Priority of ping message. + * @param ttl TTL value for network message. + */ +static void mms_ping(uint16_t destination, uint8_t seq, uint8_t prio, int ttl); + +static uint8_t mms_ping_last_proc_id; ///< Random process id of last ping request +static uint8_t mms_ping_packets; ///< Number of ping replies received +static int mms_ping_dups; ///< Duplicates +static bool ping_bc_mode; ///< If option -b is set and address is BC +static bool ping_silent_mode; ///< If option -s is set +static bool* dups; ///< Helper buffer to check for DUPs +static float rtt_min; ///< Min. RTT +static float rtt_max; ///< Max. RTT +static float rtt_avg; ///< Avg. RTT + +static struct utimer mms_ping_utimer; ///< utimer for ping +static uint16_t mms_ping_pid; ///< Process ID of process ping is running within + +/*---------------------------------------------------------------------------*/ +// Data structures for build in SSH +/*---------------------------------------------------------------------------*/ + +#define MMS_SSH_CON_REQUEST (1) ///< SSH type: connection request +#define MMS_SSH_CON_ACCEPT (2) ///< SSH type: connection accept +#define MMS_SSH_CON_REJECT (3) ///< SSH type: connection reject +#define MMS_SSH_CON_CLOSE (4) ///< SSH type: connection close +#define MMS_SSH_DATA (5) ///< SSH type: data packet + +#define MMS_SSH_DATA_MAX (43) ///< Maximum SSH data packet size + +/** + * Represents a SSH message. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct __attribute__ ((packed)) mms_ssh_message_t +{ + uint8_t type; ///< Type of SSH message +} mms_ssh_message_t; + +/** + * Represents a SSH data message. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Data | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +typedef struct __attribute__ ((packed)) mms_ssh_data_message_t +{ + uint8_t type; ///< Type of SSH message + uint8_t data[MMS_SSH_DATA_MAX]; ///< Message information +} mms_ssh_data_message_t; + +/** + * @brief Make SSH connection request with given node. + * + * @param destination The destination address. + */ +static void mms_ssh_connect(uint16_t destination); + +/** + * @brief Accept or reject SSH connection request. + * + * @param destination The destination address. + * @param socket The socket to use or -1. + * @param accept Whether to accept or reject the connection request. + */ +static void mms_ssh_reply_connect(uint16_t destination, int socket, bool accept); + +/** + * @brief Close SSH connection. + * + * @param destination The destination address. + */ +static void mms_ssh_close(uint16_t destination); + +static volatile int ssh_socket = -1; + +/*---------------------------------------------------------------------------*/ +// Interface definitions +/*---------------------------------------------------------------------------*/ + +static route_interface_t r_iface = { + rt_add_route, + rt_add_fix_route, + rt_lookup_route, + mmr_peek, + mmr_send, + mmr_packet_dropped, + mmr_receive, + mmr_print_stats +}; + +/*---------------------------------------------------------------------------*/ +// Build in MMS commands +/*---------------------------------------------------------------------------*/ + +//#if CMD_ISLEVEL(CMD_LEVEL_SYSTEM_DEBUG | CMD_LEVEL_HUMAN_USER | CMD_LEVEL_OPERATION) +ASCCMD(route, CMDFLAG_SERIAL, "[-adfFg] print kernel route table"); +CMD_FUNCTION(route, cmdargs) +{ + if (cmdargs->arg_size > 0) + { + char* msg = (char*)cmdargs->args; + while (*msg == ' ') msg++; + if (*msg == '-' && *(msg+1) == 'f') + { + mms_flush_routes(false); + printf("Kernel route table flushed (non-static)!\n"); + return CMD_SUCCESS; + } + else if (*msg == '-' && *(msg+1) == 'F') + { + mms_flush_routes(true); + printf("Kernel route table flushed (static)!\n"); + return CMD_SUCCESS; + } + else if (*msg == '-' && *(msg+1) == 'd') + { + msg++; msg++; + while (*msg == ' ') msg++; + uint16_t address = net_strtoaddr(msg, &msg); + if (rt_remove_static_route(address)) { + printf("Static route deleted successfully!\n"); + return CMD_SUCCESS; + } + return CMD_ERROR; + } + else if (*msg == '-' && *(msg+1) == 'g') + { + msg++; msg++; + while (*msg == ' ') msg++; + uint16_t address = net_strtoaddr(msg, &msg); + int c = rt_remove_static_gateway_routes(address); + printf("%u static route(s) deleted!\n", c); + return CMD_SUCCESS; + } + else if (*msg == '-' && *(msg+1) == 'a') + { + msg++; msg++; + while (*msg == ' ') msg++; + uint16_t address = net_strtoaddr(msg, &msg); + uint16_t gateway = net_strtoaddr(msg, &msg); + int metric = (int)strtoul(msg, &msg, 0); + int iface = (int)strtoul(msg, &msg, 0); + if (address != 0 && gateway != 0) { + if (rt_add_static_route(address, gateway, metric, iface)) { + printf("Static route added successfully!\n"); + return CMD_SUCCESS; + } + } + return CMD_ERROR; + } + else + { + printf("Usage: route [-adfFg] print kernel route table\n\n"); + printf(" -a , add static route to kernel route table\n"); + printf(" -d , delete static route out of kernel route table\n"); + printf(" -f, flush non-static routes out of kernel route table\n"); + printf(" -F, flush static routes out of kernel route table\n"); + printf(" -g , delete static routes out of kernel route table with a\n" + " specific gateway\n\n"); + printf(" = destination network address\n"); + printf(" = gateway network address\n"); + printf(" = metric, e.g. number of hops\n"); + printf(" = network interface number\n\n"); + return CMD_ERROR; + } + } + else + { + mms_print_routes(); + return CMD_SUCCESS; + } +} + +ASCCMD(ifconfig, CMDFLAG_SERIAL, "[IFACE]: print interface configuration"); +CMD_FUNCTION(ifconfig, cmdargs) +{ + if (cmdargs->arg_size > 0) + { + char* msg; + int iface = (int)strtoul(cmdargs->args, &msg, 0); + if (cmdargs->arg_size > 1) + { + while (*msg == ' ') msg++; + if (*msg == '-' && (*(msg+1) == 'P' || *(msg+1) == 'p')) + { + msg++; msg++; + uint8_t power = (uint8_t)strtoul(msg, &msg, 0); + if (*msg != '\0') return CMD_ERROR; + if (mms_set_output_power(iface, power)) + { + printf("Output power set!\n"); + return CMD_SUCCESS; + } + return CMD_ERROR; + } + else if (*msg == '-' && (*(msg+1) == 'A' || *(msg+1) == 'a')) + { + msg++; msg++; + while (*msg == ' ') msg++; + uint16_t address = net_strtoaddr(msg, &msg); + if (mms_set_interface_address(iface, address)) + { + printf("Interface address set!\n"); + return CMD_SUCCESS; + } + return CMD_ERROR; + } + else + { + printf("Usage: ifconfig [IFACE] [-AP] print interface configuration\n\n"); + printf(" -A , set interface address, e.g. ifconfig 0 -A 1.1\n"); + printf(" -P , set output power on interface\n\n"); + return CMD_ERROR; + } + } + else + { + mms_print_ifconfig(iface); + } + } + else + { + mms_print_ifconfig(-1); + } + return CMD_SUCCESS; +} + +ASCCMD(ping, CMDFLAG_SERIAL, "ping [-bchpstw] destination"); +CMD_FUNCTION(ping, cmdargs) +{ + if (cmdargs->arg_size > 0) + { + int i; + msg m; + uint8_t count = MMS_PING_PACKETS; + uint8_t prio = PRIORITY_DATA; + bool bc = false; + ping_bc_mode = false; + ping_silent_mode = false; + int ttl = 10; + long timeout = 3; + char adrbuf[10]; + const char* msg = cmdargs->args; + read_ping_cmd: + while (*msg == ' ') msg++; + if (*msg == '-' && (*(msg+1) == 'B' || *(msg+1) == 'b')) { + bc = true; + msg++; msg++; + goto read_ping_cmd; + } else if (*msg == '-' && (*(msg+1) == 'C' || *(msg+1) == 'c')) { + msg++; msg++; + unsigned long tc = strtoul(msg, (char**)&msg, 0); + if (tc == 0) return CMD_ERROR; + if (tc > 255) { + puts("Not more than 255 ping messages allowed!"); + return CMD_ERROR; + } + count = (uint8_t) tc; + goto read_ping_cmd; + } else if (*msg == '-' && (*(msg+1) == 'H' || *(msg+1) == 'h')) { + printf("Usage: ping [-bchpstw] destination\n\n"); + printf(" -b, do a broadcast ping\n"); + printf(" -c , set number of ping messages\n"); + printf(" -h, print a help synopsis\n"); + printf(" -p , set the ping message priority\n"); + printf(" PRIO = 1: alarm\n"); + printf(" PRIO = 2: warning\n"); + printf(" PRIO = 3: data (default)\n"); + printf(" -s, silent mode (no messages printed out)\n"); + printf(" -t , TTL value of ping messages (default: 10)\n"); + printf(" -w , time to wait for a response, in seconds (default: 3)\n\n"); + return CMD_SUCCESS; + } else if (*msg == '-' && (*(msg+1) == 'p' || *(msg+1) == 'P')) { + msg++; msg++; + unsigned long tp = strtoul(msg, (char**)&msg, 0); + if (tp == 0) return CMD_ERROR; + if (tp == 1) prio = 0; + else if (tp == 2) prio = 1; + else prio = 2; + goto read_ping_cmd; + } else if (*msg == '-' && (*(msg+1) == 's' || *(msg+1) == 'S')) { + ping_silent_mode = true; + msg++; msg++; + goto read_ping_cmd; + } else if (*msg == '-' && (*(msg+1) == 't' || *(msg+1) == 'T')) { + msg++; msg++; + unsigned long to = strtoul(msg, (char**)&msg, 0); + if (to == 0 || to > 255) return CMD_ERROR; + ttl = to; + goto read_ping_cmd; + } else if (*msg == '-' && (*(msg+1) == 'w' || *(msg+1) == 'W')) { + msg++; msg++; + unsigned long to = strtoul(msg, (char**)&msg, 0); + if (to == 0) return CMD_ERROR; + timeout = to; + goto read_ping_cmd; + } + uint16_t address = net_strtoaddr((char*)msg, (char**)&msg); + if (address == 0) return CMD_ERROR; + int iface_addr = net_get_address_in_subnet(address); + // No ping to unsupported network or own address + if (iface_addr == 0 || iface_addr == address) return CMD_ERROR; + // If broadcast destination address, limit TTL to one hop + if (address == NETWORK_ADDR_BC(address)) { + if (!bc) { + puts("Do you want to ping broadcast? Then -b"); + return CMD_ERROR; + } + ttl = 1; + ping_bc_mode = true; + } + // Try to malloc duplicate detection buffer + dups = (bool*) malloc(count * sizeof(bool)); + if (dups == NULL) { + puts("Not enough system memory to fulfill your request!"); + return CMD_ERROR; + } + net_addrtostr(address, adrbuf, sizeof(adrbuf)); + printf("PING %s %lu bytes of data.\n", adrbuf, sizeof(mms_ping_message_t)); + mms_ping_packets = 0; + mms_ping_dups = 0; + mms_ping_last_proc_id = (rand() % 255) + 1; + rtt_min = 0xffffffff; + rtt_max = 0x00000000; + rtt_avg = 0x00000000; + mms_ping_pid = fk_thread->pid; + long ts_start = (uint32_t)clock_get_systemtime(); + for (i = 1; i <= count; i++) + { + // No duplicate for this sequence number possible + dups[i-1] = false; + // Send ping echo request to destination + mms_ping(address, i, prio, ttl); + // Set timeout for next ping echo request packet to ::timeout seconds + utimer_set_wpid(&mms_ping_utimer, timeout, mms_ping_pid, NULL); + // Wait for ping echo reply or timeout + msg_receive(&m); + // Remove user timer because maybe woken up by ping response + utimer_remove(&mms_ping_utimer); + } + ts_start = (uint32_t)clock_get_systemtime() - ts_start; + printf("--- %s ping statistics ---\n", adrbuf); + if (mms_ping_dups == 0) { + printf("%u packets transmitted, %u received, %u%% packet loss, time %lu ms\n", count, + mms_ping_packets, ((count-mms_ping_packets)*100)/count, ts_start); + } else { + printf("%u packets transmitted, %u received, +%i duplicates, %u%% packet loss, time %lu ms\n", count, + mms_ping_packets, mms_ping_dups, ((count-mms_ping_packets)*100)/count, ts_start); + } + if (mms_ping_packets > 0) + { + printf("rtt min/avg/max = %.2f/%.2f/%.2f ms\n", rtt_min, rtt_avg/(mms_ping_packets+mms_ping_dups), rtt_max); + } + if (!ping_bc_mode && mms_ping_packets == count) { + // Calculate approximate throughput + printf("--- %s throughput statistics ---\n", adrbuf); + float bw = (count * (8+4+62+2) * 1000) / (float)ts_start; // for CC1100 + printf("approximate throughput (air): %.2f byte/sec\n", 2*bw); + bw = (count * 58 * 1000) / (float)ts_start; // for CC1100 + printf("approximate throughput (dll): %.2f byte/sec\n", 2*bw); + bw = (count * NET_MESSAGE_PAYLOAD_LENGTH * 1000) / (float)ts_start; + printf("approximate throughput (net): %.2f byte/sec\n", 2*bw); + bw = (count * UDPL_MESSAGE_LENGTH * 1000) / (float)ts_start; + printf("approximate throughput (trans/UDPL): %.2f byte/sec\n", 2*bw); + bw = (count * TCPL_MESSAGE_LENGTH * 1000) / (float)ts_start; + printf("approximate throughput (trans/TCPL): %.2f byte/sec\n", bw); + } + // Ping is over, clear random ping process id and buffer + mms_ping_last_proc_id = 0; + free(dups); + return CMD_SUCCESS; + } + return CMD_ERROR; +} + +ASCCMD(ssh, CMDFLAG_SERIAL, "Usage: ssh [-q] destination"); +CMD_FUNCTION(ssh, cmdargs) +{ + if (cmdargs->arg_size > 0) { + bool quit = false; + const char* msg = cmdargs->args; + while (*msg == ' ') msg++; + if (*msg == '-' && (*(msg+1) == 'Q' || *(msg+1) == 'q')) + { + quit = true; + msg++; msg++; + } + uint16_t address = net_strtoaddr((char*)msg, (char**)&msg); + if (address == 0) return CMD_ERROR; + int iface_addr = net_get_address_in_subnet(address); + // No ssh to unsupported network or own address + if (iface_addr == 0 || iface_addr == address) return CMD_ERROR; + // If broadcast destination address, also exit here + if (address == NETWORK_ADDR_BC(address)) return CMD_ERROR; + if (!quit) { + mms_ssh_connect(address); + } else { + mms_ssh_close(address); + } + return CMD_SUCCESS; + } + return CMD_ERROR; +} +//#endif + +/*---------------------------------------------------------------------------*/ +// Ping message handler and send function +/*---------------------------------------------------------------------------*/ + +static void mms_ping_handler(void* message, int message_size, packet_info_t* packet_info) +{ + mms_ping_message_t* ping = (mms_ping_message_t*)message; + if (ping->type == MMS_PING_ECHO_REQUEST) + { + ping->type = MMS_PING_ECHO_REPLY; + net_send((void*)ping, sizeof(mms_ping_message_t), packet_info->source, + LAYER_2_PROTOCOL_PING, packet_info->tos, 10); + } + else if (ping->type == MMS_PING_ECHO_REPLY) + { + if (ping->identifier == mms_ping_last_proc_id) + { + msg m; + bool wasDup = false; + char* msgDup; + char buf[10]; + + if (dups[ping->seq_num-1]) { + wasDup = true; + mms_ping_dups++; + msgDup = "(DUP!)"; + } else { + mms_ping_packets++; + dups[ping->seq_num-1] = true; + msgDup = ""; + } + + if (!ping_bc_mode && !wasDup) { + utimer_remove(&mms_ping_utimer); // Stop timeout timer + } + + float ms = ((uint32_t)clock_get_systemtime() - ping->timestamp); + if (ms < rtt_min) rtt_min = ms; + if (ms > rtt_max) rtt_max = ms; + rtt_avg += ms; + if (!ping_silent_mode) { + net_addrtostr(packet_info->source, buf, sizeof(buf)); + printf("%lu bytes from %s: seq=%u ttl=%u time=%.2f ms %s\n", + sizeof(mms_ping_message_t), buf, + ping->seq_num, *packet_info->ttl_ptr, ms, msgDup); + } + if (!ping_bc_mode && !wasDup) msg_send(&m, mms_ping_pid, false); + } + } +} + +static void mms_ping(uint16_t destination, uint8_t seq, uint8_t prio, int ttl) +{ + mms_ping_message_t ping_request; + ping_request.type = MMS_PING_ECHO_REQUEST; + ping_request.identifier = 0; + ping_request.identifier = mms_ping_last_proc_id; + ping_request.seq_num = seq; + ping_request.timestamp = (uint32_t)clock_get_systemtime(); + net_send((void*)&ping_request, sizeof(mms_ping_message_t), + destination, LAYER_2_PROTOCOL_PING, prio, ttl); +} + +/*---------------------------------------------------------------------------*/ +// SSH message handler and send functions +/*---------------------------------------------------------------------------*/ + +static void mms_ssh_connect(uint16_t destination) +{ + mms_ssh_message_t ssh; + ssh.type = MMS_SSH_CON_REQUEST; + mms_send((void*)&ssh, sizeof(mms_ssh_message_t), destination, + LAYER_3_PROTOCOL_SSH, PRIORITY_DATA); +} + +static void mms_ssh_reply_connect(uint16_t destination, int socket, bool accept) +{ + mms_ssh_message_t ssh; + ssh.type = accept ? MMS_SSH_CON_ACCEPT : MMS_SSH_CON_REJECT; + trans_sendto(socket, (void*)&ssh, sizeof(mms_ssh_message_t), + LAYER_3_PROTOCOL_SSH, PRIORITY_DATA, destination); +} + +static void mms_ssh_close(uint16_t destination) +{ + mms_ssh_message_t ssh; + ssh.type = MMS_SSH_CON_CLOSE; + mms_send((void*)&ssh, sizeof(mms_ssh_message_t), destination, + LAYER_3_PROTOCOL_SSH, PRIORITY_DATA); +} + +static void mms_ssh_handler(void* message, int message_size, packet_info_t* packet_info) +{ + char adrbuf[10]; + mms_ssh_message_t* ssh = (mms_ssh_message_t*)message; + if (ssh->type == MMS_SSH_CON_REQUEST) { + if (ssh_socket > -1) { + mms_ssh_reply_connect(packet_info->source, -1, false); + return; + } + ssh_socket = trans_socket(SOCK_TCPL); + if (ssh_socket < 0) { + mms_ssh_reply_connect(packet_info->source, -1, false); + return; + } + trans_connect(ssh_socket, packet_info->source); + mms_ssh_reply_connect(packet_info->source, ssh_socket, true); + } else if (ssh->type == MMS_SSH_CON_ACCEPT) { + net_addrtostr(packet_info->source, adrbuf, sizeof(adrbuf)); + printf("SSH connection accepted by %s\n", adrbuf); + } else if (ssh->type == MMS_SSH_CON_REJECT) { + net_addrtostr(packet_info->source, adrbuf, sizeof(adrbuf)); + printf("SSH connection rejected by %s\n", adrbuf); + } else if (ssh->type == MMS_SSH_CON_CLOSE) { + if (ssh_socket > -1) { + uint16_t peer; + trans_getpeername(ssh_socket, &peer); + if (peer == packet_info->source) { + if (trans_close(ssh_socket, CLOSE_IMMEDIATE) == 1) { + ssh_socket = -1; + } + } + } + } else if (ssh->type == MMS_SSH_DATA) { + mms_ssh_data_message_t* ssh_data = (mms_ssh_data_message_t*)message; + printf((char*)ssh_data->data); + fflush(stderr); + } +} + +void mms_net_printf(const char * format) +{ + if (ssh_socket > -1) { + mms_ssh_data_message_t ssh_data; + ssh_data.type = MMS_SSH_DATA; + int i = 0; + int len = strlen(format); + while (i < len) { + int chunk = len - i > (MMS_SSH_DATA_MAX-1) ? (MMS_SSH_DATA_MAX-1) : len - i; + memset(ssh_data.data, 0, sizeof(ssh_data.data)); + memcpy(ssh_data.data, format + i, chunk); + if (trans_send(ssh_socket, (void*)&ssh_data, sizeof(mms_ssh_data_message_t), + LAYER_3_PROTOCOL_SSH, PRIORITY_DATA) < 0) break; + i += chunk; + } + } else { + printf(format); + } +} + +/*---------------------------------------------------------------------------*/ +// Micro Mesh Stack API +/*---------------------------------------------------------------------------*/ + +void mms_init(void) +{ + mms_initp(LAYER_2_PROTOCOL_MMR, &r_iface); +} + +void mms_initp(protocol_t rp, route_interface_t* ri) +{ + // Initialize routing & network layer + mmr_init(); + net_init(ri); + // Initialize transport layer + trans_init(); + // Add routing as protocol handler for given route messages + net_set_protocol_handler(rp, ri->receive); + // Add transport as protocol handler for UDPL and TCPL messages + net_set_protocol_handler(LAYER_2_PROTOCOL_UDPL, trans_receive_udpl); + net_set_protocol_handler(LAYER_2_PROTOCOL_TCPL, trans_receive_tcpl); + // Add MMS ping handler + net_set_protocol_handler(LAYER_2_PROTOCOL_PING, mms_ping_handler); + // Add SSH handler + trans_set_protocol_handler(LAYER_3_PROTOCOL_SSH, mms_ssh_handler); +} + +/*---------------------------------------------------------------------------*/ + +int mms_add_interface(const char* name, uint16_t addr, const radio_t* radio) +{ + return net_add_interface(name, addr, radio); +} + +/*---------------------------------------------------------------------------*/ + +uint16_t mms_get_interface_address(int interface_id) +{ + return net_get_interface_address(interface_id); +} + +/*---------------------------------------------------------------------------*/ + +bool mms_set_interface_address(int interface_id, uint16_t addr) +{ + return net_set_interface_address(interface_id, addr); +} + +/*---------------------------------------------------------------------------*/ + +bool mms_set_output_power(int interface_id, uint8_t pa_idx) +{ + return net_set_output_power(interface_id, pa_idx); +} + +/*---------------------------------------------------------------------------*/ + +int mms_set_protocol_handler(protocol_t protocol, packet_handler_t handler) +{ + return trans_set_protocol_handler(protocol, handler); +} + +/*---------------------------------------------------------------------------*/ + +void mms_receive(void* msg, int msg_size, packet_info_t* packet_info) +{ + net_receive(msg, msg_size, packet_info); +} + +/*---------------------------------------------------------------------------*/ + +int mms_socket(int type) +{ + return trans_socket(type); +} + +/*---------------------------------------------------------------------------*/ + +int mms_connect(int socket, uint16_t dest_addr) +{ + return trans_connect(socket, dest_addr); +} + +/*---------------------------------------------------------------------------*/ + +int mms_sock_send(int socket, void* buffer, int length, protocol_t protocol, uint8_t priority) +{ + return trans_send(socket, buffer, length, protocol, priority); +} + +/*---------------------------------------------------------------------------*/ + +int mms_sock_sendto(int socket, void* buffer, int length, protocol_t protocol, uint8_t priority, uint16_t dest_addr) +{ + return trans_sendto(socket, buffer, length, protocol, priority, dest_addr); +} + +/*---------------------------------------------------------------------------*/ + +int mms_send(void* msg, int msg_len, uint16_t dst, protocol_t protocol, uint8_t priority) +{ + return trans_sendto(-1, msg, msg_len, protocol, priority, dst); +} + +/*---------------------------------------------------------------------------*/ + +int mms_poll(int socket) +{ + return trans_poll(socket); +} + +/*---------------------------------------------------------------------------*/ + +int mms_close(int socket, int how) +{ + return trans_close(socket, how); +} + +/*---------------------------------------------------------------------------*/ + +void mms_flush_routes(bool flush_static) +{ + rt_flush_routes(flush_static); +} + +/*---------------------------------------------------------------------------*/ + +void mms_print_routes(void) +{ + rt_print_routes(); +} + +/*---------------------------------------------------------------------------*/ + +void mms_print_ifconfig(int iface) +{ + net_print_ifconfig(iface); +} + +/*---------------------------------------------------------------------------*/ + +void mms_print_stats(void) +{ + net_print_stats(); + printf("\r\n"); + r_iface.print_stats(); +} diff --git a/sys/net/mm/mmstack.h b/sys/net/mm/mmstack.h new file mode 100644 index 000000000..e07fa4f38 --- /dev/null +++ b/sys/net/mm/mmstack.h @@ -0,0 +1,211 @@ +/****************************************************************************** +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 +*******************************************************************************/ + +#ifndef MMSTACK_H_ +#define MMSTACK_H_ + +/** + * @defgroup net_mmstack Micro Mesh Stack + * @ingroup net + * + * @{ + */ + +/** + * @file + * @brief + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Thomas Hillebrandt + * @version $Revision: 3854 $ + * + * @note $Id: mmstack.h 3854 2011-12-06 15:27:01Z hwill $ + */ + +#include "radio.h" +#include "net-types.h" + +/** + * @brief Initialize micro mesh stack. + */ +void mms_init(void); + +/** + * @brief Initialize micro mesh stack. + * + * @param rp Routing protocol type identifier. + * @param ri Pointer to route interface. + */ +void mms_initp(protocol_t rp, route_interface_t* ri); + +/** + * @brief Add network interface. + * + * @param name Network layer name on this interface (maximum 5 characters). + * @param addr Network layer address on this interface. + * @param radio Radio layer API access. + * + * @return Interface identifier or -1 if an error occurs. + */ +int mms_add_interface(const char* name, uint16_t addr, const radio_t* radio); + +/** + * @brief Get the address of the network interface with given id. + * + * @param interface_id The network interface id. + * + * @return The address of the network interface with given id + * or 0 if no interface with given id is found. + */ +uint16_t mms_get_interface_address(int interface_id); + +/** + * @brief Set the address of the network interface with the given id. + * + * @param interface_id The network interface id. + * @param addr The new address to set. + * + * @return true if address was successfully set; false otherwise (e.g. + * wrong interface, invalid address etc.) + */ +bool mms_set_interface_address(int interface_id, uint16_t addr); + +/** + * @brief Set the output power of the radio device on the network + * interface with the given id. + * + * @param interface_id The network interface id. + * @param pa_idx Output power value from 0 (lowest output power) to + * X (highest output power). + * + * @return true if output power was successfully set; false otherwise + * (e.g. wrong interface, invalid output power value etc.) + */ +bool mms_set_output_power(int interface_id, uint8_t pa_idx); + +/** + * @brief Set a protocol handler for a given protocol. + * + * @param protocol The protocol identifier (must be unique). + * @param handler The packet handler called if a packet of given protocol is received. + * + * @return -1 if an error occurs (e.g. handler table full) else >= 0. + */ +int mms_set_protocol_handler(protocol_t protocol, packet_handler_t handler); + +/** + * @see ::trans_socket(int) + */ +int mms_socket(int type); + +/** + * @see ::trans_connect(int,uint16_t) + */ +int mms_connect(int socket, uint16_t dest_addr); + +/** + * @see ::trans_send(int,void*,int,protocol_t,uint8_t) + */ +int mms_sock_send(int socket, void* buffer, int length, protocol_t protocol, uint8_t priority); + +/** + * @see ::trans_sendto(int,void*,int,protocol_t,uint8_t,uint16_t) + */ +int mms_sock_sendto(int socket, void* buffer, int length, protocol_t protocol, uint8_t priority, uint16_t dest_addr); + +/** + * @brief Convenience function to send a message via UDPL socket. + * + * @param msg packet payload + * @param msg_len the size of the packet payload in bytes (max. 46 bytes). + * @param dst packet destination address + * @param protocol packet protocol identifier + * @param priority packet priority + * + * @return Upon successful completion, mms_send() returns a value greater zero. + * Otherwise, a negative value is returned to indicate the error. + */ +int mms_send(void* msg, int msg_len, uint16_t dst, protocol_t protocol, uint8_t priority); + +/** + * @see ::trans_poll(int) + */ +int mms_poll(int socket); + +/** + * @see ::trans_close(int,int) + */ +int mms_close(int socket, int how); + +/** + * @brief Receive function for incoming packets. + * + * This function is the protocol handler function for micro mesh messages received + * on the lower layers. + * + * @param msg Incoming packet. + * @param msg_size Size of incoming packet. + * @param packet_info Additional packet information. + */ +void mms_receive(void* msg, int msg_size, packet_info_t* packet_info); + +/** + * @brief Flush kernel route table. + * + * @param flush_static Whether to flush static routes also + */ +void mms_flush_routes(bool flush_static); + +/** + * @brief Writes to the standard output (stdout) a sequence of data formatted as + * the format argument specifies. + * + * If a SSH connection is active, the output is redirected to the node who + * initialized the SSH connection. + * + * @param format String that contains the text to be written to stdout. + */ +void mms_net_printf(const char * format); + +/** + * @brief Print kernel route table. + */ +void mms_print_routes(void); + +/** + * @brief Print interface configuration. + * + * @param iface Optional interface parameter. + */ +void mms_print_ifconfig(int iface); + +/** + * @brief Print Micro Mesh stack statistics. + */ +void mms_print_stats(void); + +/** @} */ +#endif /* MMSTACK_H_ */ diff --git a/sys/ping.c b/sys/ping.c index d68d2c903..c734ae5c9 100644 --- a/sys/ping.c +++ b/sys/ping.c @@ -3,7 +3,7 @@ #include #include -#include "drivers/cc110x/cc1100.h" +#include "cc110x/cc1100.h" #include "lpc2387.h" #include "swtimer.h" @@ -53,11 +53,11 @@ void ping(radio_address_t addr, uint8_t channr){ protocol_id,2,pipa->payload,sizeof(pipa->payload)); if(trans_ok < 0) print_failed(); - ktimer_wait(500000); + hwtimer_wait(500000); } } -void calc_rtt(){ +void calc_rtt(void){ uint64_t end = swtimer_now(); rtt = ((float)end - (float)start)/1000; diff --git a/sys/shell/makefile b/sys/shell/makefile new file mode 100644 index 000000000..982135d36 --- /dev/null +++ b/sys/shell/makefile @@ -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 + + diff --git a/sys/swtimer.c b/sys/swtimer.c index 4dc248515..9693e03a8 100644 --- a/sys/swtimer.c +++ b/sys/swtimer.c @@ -30,13 +30,13 @@ /* workaround for buggy mspgcc signal.h */ #undef wakeup -static void swtimer_update_alarm(); +static void swtimer_update_alarm(void); static void swtimer_action(swtimer_t *swtimer); static void swtimer_trigger(void* ptr); static void swtimer_tick(void *ptr); static int swtimer_activate(swtimer_t *t); static void swtimer_priolist_insert(swtimer_t *t); -static void swtimer_update_values(); +static void swtimer_update_values(void); static swtimer_t *swtimer_list = NULL; static volatile swtime_t system_time = 0; @@ -46,7 +46,7 @@ static volatile int hwtimer_id = -1; extern unsigned long hwtimer_now(void); -int swtimer_init() { +int swtimer_init(void) { hwtimer_set_absolute(HWTIMER_MAXTICKS, swtimer_tick, NULL); return 0; } @@ -84,7 +84,7 @@ static int swtimer_activate(swtimer_t *t) { return 0; } -static void swtimer_update_values() { +static void swtimer_update_values(void) { swtimer_next_alarm_absolute = swtimer_list->start + swtimer_list->interval; swtime_t now = swtimer_now(); swtime_t offset = swtimer_next_alarm_absolute - now; @@ -125,7 +125,7 @@ int swtimer_remove(swtimer_t *t) { return 0; } -swtime_t swtimer_now() { +swtime_t swtimer_now(void) { swtime_t now = system_time; now += HWTIMER_TICKS_TO_US(hwtimer_now()); return now; @@ -254,7 +254,7 @@ static void swtimer_trigger(void* ptr) { } -static void swtimer_update_alarm() { +static void swtimer_update_alarm(void) { DEBUG("swtimer_check_elapsed: Checking for elapsed timer...\n"); while (swtimer_list) { diff --git a/sys/syslog/makefile b/sys/syslog/makefile new file mode 100644 index 000000000..968486c1c --- /dev/null +++ b/sys/syslog/makefile @@ -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 =syslog + +include $(MAKEBASE)/makefile.base + + diff --git a/sys/syslog/syslog-api.c b/sys/syslog/syslog-api.c new file mode 100644 index 000000000..8b3c9a43f --- /dev/null +++ b/sys/syslog/syslog-api.c @@ -0,0 +1,112 @@ +/****************************************************************************** +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 +*******************************************************************************/ + +#include +#include "syslog.h" +#include "tracelog.h" + +#undef VSYSLOG +#define VSYSLOG(level, strModule, strFmt, argp) vsyslog(level, strModule, strFmt, argp) + +void +syslog( + const uint8_t level, + const char (*const strModule), + const char* strFmt, ... +) { + va_list argp; + + va_start(argp, strFmt); + VSYSLOG(level, strModule, strFmt, argp); + va_end(argp); +} +/*-----------------------------------------------------------------------------------*/ +#if (SYSLOG_CONF_LEVEL & SL_EMERGENCY) == SL_EMERGENCY +void syslog_emergency(const char (*const mod), const char* strFmt, ...) +{ + va_list argp; + + va_start(argp, strFmt); + VSYSLOG(SL_EMERGENCY, mod, strFmt, argp); + va_end(argp); +} +#endif +/*-----------------------------------------------------------------------------------*/ +#if (SYSLOG_CONF_LEVEL & SL_CRITICAL) == SL_CRITICAL +void syslog_critical(const char (*const mod), const char* strFmt, ...) +{ + va_list argp; + + va_start(argp, strFmt); + VSYSLOG(SL_CRITICAL, mod, strFmt, argp); + va_end(argp); +} +#endif +/*-----------------------------------------------------------------------------------*/ +#if (SYSLOG_CONF_LEVEL & SL_WARN) == SL_WARN +void syslog_warn(const char (*const mod), const char* strFmt, ...) +{ + va_list argp; + + va_start(argp, strFmt); + VSYSLOG(SL_WARN, mod, strFmt, argp); + va_end(argp); +} +#endif +/*-----------------------------------------------------------------------------------*/ +#if (SYSLOG_CONF_LEVEL & SL_NOTICE) == SL_NOTICE +void syslog_notice(const char (*const mod), const char* strFmt, ...) +{ + va_list argp; + + va_start(argp, strFmt); + VSYSLOG(SL_NOTICE, mod, strFmt, argp); + va_end(argp); +} +#endif +/*-----------------------------------------------------------------------------------*/ +#if (SYSLOG_CONF_LEVEL & SL_INFO) == SL_INFO +void syslog_info(const char (*const mod), const char* strFmt, ...) +{ + va_list argp; + + va_start(argp, strFmt); + VSYSLOG(SL_INFO, mod, strFmt, argp); + va_end(argp); +} +#endif +/*-----------------------------------------------------------------------------------*/ +#if SYSLOG_ISLEVEL(SL_DEBUG) +void syslog_debug(const char (*const mod), const char* strFmt, ...) +{ + va_list argp; + + va_start(argp, strFmt); + VSYSLOG(SL_DEBUG, mod, strFmt, argp); + va_end(argp); +} +#endif + diff --git a/sys/syslog/syslog-out.c b/sys/syslog/syslog-out.c new file mode 100644 index 000000000..6253425c7 --- /dev/null +++ b/sys/syslog/syslog-out.c @@ -0,0 +1,179 @@ +/****************************************************************************** +Copyright 2008-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 + * @ingroup syslog + * @brief System Logging Service output implementation + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @version $Revision: 3854 $ + * + * @note $Id: syslog-out.c 3854 2011-12-06 15:27:01Z hwill $ + */ + +#include +#include +#ifdef MODULE_FAT +#include +#include +#include +#endif +// sys +#include "cfg-feuerware.h" +#include "syslog.h" +#include "clock.h" +#include "device-rs232.h" +#if FEUERWARE_CONF_CORE_SUPPORTS_TIME +#include "timelib.h" +#endif +// net +#include "net-types.h" +#ifdef MODULE_TRACELOG +#include "tracelog.h" +#endif + +/*-----------------------------------------------------------------------------------*/ +void +syslog_format_ascii(struct syslog_args* args, struct syslog_chainlink* chainlink) +{ + char buffer[SYSLOG_CONF_BUFSIZE + 25]; + int msglen = 0; + + if( args->message[0] != '\t' ) { + const char* strlevel = syslog_leveltostring(args->level); + msglen = snprintf(buffer, SYSLOG_CONF_BUFSIZE + 23, + "#[%u.%u:%u=%s] %s:", + NETWORK_ADDR_NET(NET_LOCAL_ADDRESS), NETWORK_ADDR_HOST(NET_LOCAL_ADDRESS), + args->level, strlevel, args->module + ); + } + + msglen += snprintf(buffer + msglen, SYSLOG_CONF_BUFSIZE + 23 - msglen, "%s", args->message); + buffer[msglen++] = '\n'; + buffer[msglen] = '\0'; + + args->message = buffer; + if( chainlink != NULL && chainlink->fpout != NULL ) + chainlink->fpout(args, chainlink->next); +} +/*-----------------------------------------------------------------------------------*/ +void +syslog_format_xml(struct syslog_args* args, struct syslog_chainlink* chainlink) +{ + const size_t bufsize = SYSLOG_CONF_BUFSIZE + 80; + char buffer[bufsize]; + char tbuf[20]; + int msglen = 0; + + #if FEUERWARE_CONF_CORE_SUPPORTS_TIME + time_get_string(tbuf, sizeof(tbuf)); + #else + sprintf(tbuf, "%lu", clock_time(NULL)); + #endif + + msglen = snprintf(buffer, bufsize, + "%s\n", + args->level, NETWORK_ADDR_NET(NET_LOCAL_ADDRESS), NETWORK_ADDR_HOST(NET_LOCAL_ADDRESS), + args->msgnum, tbuf, args->module, args->message + ); + + args->message = buffer; + if( chainlink != NULL && chainlink->fpout != NULL ) + chainlink->fpout(args, chainlink->next); +} +/*-----------------------------------------------------------------------------------*/ +void +syslog_copy_stdout(struct syslog_args* args, struct syslog_chainlink* chainlink) +{ + if( args->message[0] != '\t' ) { + const char* strlevel = syslog_leveltostring(args->level); + printf("#[%u.%u:%u=%s] %s:", + NETWORK_ADDR_NET(NET_LOCAL_ADDRESS), NETWORK_ADDR_HOST(NET_LOCAL_ADDRESS), + args->level, strlevel, args->module + ); + } + printf("%s\n", args->message); + + if( chainlink != NULL && chainlink->fpout != NULL ) + chainlink->fpout(args, chainlink->next); +} +/*-----------------------------------------------------------------------------------*/ +void +syslog_out_stdout(struct syslog_args* args, struct syslog_chainlink* chainlink) +{ + printf(args->message); + + if( chainlink != NULL && chainlink->fpout != NULL ) + chainlink->fpout(args, chainlink->next); +} +/*-----------------------------------------------------------------------------------*/ +#ifdef MODULE_FAT +static int syslog_file = -1; + +static int fat_open_logfile(const char* path); +static int fat_open_logfile(const char* path) +{ + char t[20]; + int file; + + file = open(path, O_WRONLY | O_APPEND | O_CREAT); + + time_get_string(t, sizeof(t)); + + if( file >= 0 ) { + syslog_notice("sys", "%s log %s opened", t, path); + } else { + syslog_warn("sys", "%s log %s failed", t, path); + } + return file; +} + +void syslog_out_file(struct syslog_args* args, struct syslog_chainlink* chainlink) +{ + if( syslog_file >= 0 ) { + size_t length = (size_t)strlen(args->message); + int ret = write(syslog_file, args->message, length); + if( ret == 1 ) { +#ifdef MODULE_TRACELOG + trace_string(TRACELOG_EV_MEMORY, "fat"); +#endif + } + } + + if( chainlink != NULL && chainlink->fpout != NULL ) + chainlink->fpout(args, chainlink->next); +} + +bool syslog_open_file(void) { + syslog_file = fat_open_logfile("SYSLOG.LOG"); + return (syslog_file >= 0); +} +void syslog_close_file(void) { + close(syslog_file); + syslog_file = -1; +} +#endif diff --git a/sys/syslog/syslog.c b/sys/syslog/syslog.c new file mode 100644 index 000000000..31ed0a0cb --- /dev/null +++ b/sys/syslog/syslog.c @@ -0,0 +1,264 @@ +/****************************************************************************** +Copyright 2008-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 +*******************************************************************************/ + +/** + * @addtogroup syslog + * @{ + */ + +/** + * @file + * @brief System Logging Service implementation + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Michael Baar + * @version $Revision: 3854 $ + * + * @note $Id: syslog.c 3854 2011-12-06 15:27:01Z hwill $ + */ + +#include +#include +#include +#include + +#include "cfg-feuerware.h" +#include "cmdengine.h" +#include "device-rs232.h" +#include "syslog.h" +#include "sysmon.h" +#include "tracelog.h" + +static const char* syslog_level_stringtable = "emergency\0" + "critical\0" + "warn\0" + "notice\0" + "info\0" + "debug\0" + "\3"; + +__attribute__((section(".noinit"))) +static volatile unsigned int syslog_msgnum; + +static unsigned short syslog_flagtolevel(const uint8_t level); +static int find_interface_index_for_name(const char* name); + +extern struct syslog_interface syslog_interfaces[]; + +/*-----------------------------------------------------------------------------------*/ +void +syslog_init(void) +{ + if( sysmon_initial_boot() ) + syslog_msgnum = 0; +} +/*-----------------------------------------------------------------------------------*/ +static bool +testlevel(uint8_t filter_level, const uint8_t level) { + return ((filter_level & level) != 0); +} +/*-----------------------------------------------------------------------------------*/ +void +vsyslog( + const uint8_t level, + const char (*const strModule), + const char* strFmt, + va_list argp +) { + int i; + struct syslog_interface* slif; // syslog interface + struct syslog_args args; // output function arguments + char message[SYSLOG_CONF_BUFSIZE]; // message buffer + int msglen = 0; + + args.message = NULL; + + //printf("0 %p %p\n", &syslog_interfaces[0], syslog_interfaces[0].chain); + //printf("1 %p %p\n", &syslog_interfaces[1], syslog_interfaces[1].chain); + + // check each syslog interface + for( i = 0; i < SYSLOG_CONF_NUM_INTERFACES; i++) { + slif = &syslog_interfaces[i]; + /* run interface filter */ + //printf("testing %i, %s\n", i, slif->name); + if( slif->name != NULL && testlevel(cfg_feuerware.level[i], level) ) { + /* filter matched, produce output */ + //printf("printing to %s\n", slif->name); + if( args.message == NULL ) { + // initialize structure one time, when actually needed + args.msgnum = syslog_msgnum++; + args.level = syslog_flagtolevel(level); + args.module = strModule; + args.message = message; + msglen = vsnprintf(message, SYSLOG_CONF_BUFSIZE-1, strFmt, argp); + } + //printf("msg %i: %s\n", msglen, message); + args.interface = (const struct syslog_interface*)slif; + + // invoke first link of ouput chain + //printf("invoke on %s: %p %p\n", slif->name, slif, slif->chain); + if( slif->chain->fpout != NULL ) { + slif->chain->fpout(&args, slif->chain->next); + } + } + } +} +/*-----------------------------------------------------------------------------------*/ +void syslog_printlevel(char* buffer, size_t bufsize, uint8_t level) +{ + uint8_t l = level; + int intlevel; + int bufpos; + int len = 0; + + bufpos = snprintf(buffer, bufsize, "%#.2x=", level); + bufsize -= bufpos; + for( intlevel = 0; intlevel < SYSLOG_LEVELS_COUNT; intlevel++ ) { + if( l & 0x0001 ) { + const char* string = string_table_get(syslog_level_stringtable, intlevel); + if( string ) { + if( bufsize < 0 ) bufsize = 0; + len = snprintf( &buffer[bufpos], bufsize, "%s%s", ((len > 0) ? "|" : ""), (char*)string ); + bufsize -= len; + bufpos += len; + } + } + l >>= 1; + } +} +/*-----------------------------------------------------------------------------------*/ +uint8_t syslog_set_level(const char* name, uint8_t level) +{ + uint8_t result; + int index = find_interface_index_for_name(name); + if( index < 0 ) + return 0; + + result = cfg_feuerware.level[index]; + cfg_feuerware.level[index] = level; + cfg_feuerware_spec.state->modified = 1; + + return result; +} +/*-----------------------------------------------------------------------------------*/ +const char* +syslog_leveltostring(unsigned int level) { + return string_table_get(syslog_level_stringtable, level); +} +/*-----------------------------------------------------------------------------------*/ + +#if CMD_ISLEVEL(CMD_LEVEL_HUMAN_USER) +/** + * @brief Syslog-level property: syslog [interface] [newlevel] + * @ingroup commands + * @param[in] interface Name of the syslog interface to change (optional) + * @param[in] newlevel New loglevel value (see uint8_t) + * @return Current level + * + * \p Returns and optionally sets the syslog log-level. For available combinations see + * uint8_t. + * + * \p Usage: + * \li \c syslog Prints syslog configuration + * \li \c syslog \c 0x3f Sets loglevel of syslog node 0 (usually stdout) to 0x3f + * \li \c syslog \c stdout \c 0x3f Sets loglevel of syslog node "stdout" to 0x3f + */ +ASCCMD(syslog, 0, "[interface] [byte val]: syslog-level property"); +CMD_FUNCTION(syslog, cmdargs) +{ + int i; + + if( cmdargs->arg_size > 0 ) { + unsigned int argc; + const char* arg; + const char* name = NULL; + unsigned int value; + + argc = cmd_split_arguments(cmdargs->args); + arg = cmdargs->args; + + if( *arg >= 'A' ) { + // first argument is a string + name = arg; + // move to next argument + arg = cmd_get_next_argument(arg); + } + if( *arg == '\0' ) + return CMD_ERROR; + value = strtoul(arg, NULL, 0); + syslog_set_level(name, value); + } + + for( i = 0; i < SYSLOG_CONF_NUM_INTERFACES; i++ ) { + if( syslog_interfaces[i].name != NULL ) { + char buf[SYSLOG_PRINTLEVEL_MAXLEN]; + syslog_printlevel(buf, sizeof(buf), cfg_feuerware.level[i]); + cmdargs->fresponse(cmdargs, + CMD_RESPONSE_MULTILINE, + "%s:%s", + syslog_interfaces[i].name, + buf + ); + } + } + return CMD_SUCCESS; +} +#endif +/*-----------------------------------------------------------------------------------*/ +/** + * @brief Convert bit flag to bit number + */ +static unsigned short +syslog_flagtolevel(const uint8_t level) +{ + uint8_t l = level; + unsigned short intlevel; + + for( intlevel = 0; intlevel < SYSLOG_LEVELS_COUNT; intlevel++ ) { + if( (l & 1) == 1 ) + break; + l >>= 1; + } + + return intlevel; +} +/*-----------------------------------------------------------------------------------*/ +/** + * @brief Find an interface for a given name + */ +static int +find_interface_index_for_name(const char* name) +{ + int i; + + for( i = 0; i < SYSLOG_CONF_NUM_INTERFACES; i++ ) { + if( strcmp(syslog_interfaces[i].name, name) == 0 ) + return i; + } + return -1; +} + +/** @} */ diff --git a/sys/tracelog/makefile b/sys/tracelog/makefile new file mode 100644 index 000000000..899971b57 --- /dev/null +++ b/sys/tracelog/makefile @@ -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 =tracelog + +include $(MAKEBASE)/makefile.base + + diff --git a/sys/tracelog/tracelog.c b/sys/tracelog/tracelog.c new file mode 100644 index 000000000..a1f88afe3 --- /dev/null +++ b/sys/tracelog/tracelog.c @@ -0,0 +1,274 @@ +/****************************************************************************** +Copyright 2008, 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 +*******************************************************************************/ + +/** + * @ingroup tracelog + * @{ + */ + +/** + * @file + * @brief Tracelog implementation + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Michael Baar + * + * @note $Id: tracelog.c 3854 2011-12-06 15:27:01Z hwill $ + */ + +#include +#include +#include +#include +#include "configure.h" +// core +#include "sysmon.h" +#include "cmdengine.h" +#include "tracelog.h" +#include "stringlib.h" +#include "syslog.h" + +#if TRACELOG_CONF_NUM_ENTRIES > 0 + __attribute__((section(".noinit"))) + struct tracelog tracelog; + + /// tells if tracelog can accept input + static bool tracelog_initialized = 0; +#endif + +#if defined(SYSLOG_CONF_LEVEL) && ((SYSLOG_CONF_LEVEL & SL_DEBUG) == SL_DEBUG) +static const char symon_event_names[] = + "\0" + "start\0" + "exit\0" + "assert\0" + "event\0" + "timer\0" + "irqdis\0" + "irqen\0" + "irq\0" + "switch\0" + "\0" + "memory\0" + "memaccess\0" + "opfault\0" + "panic\0" + "userdef\0" + "\3"; +#endif + +/*-----------------------------------------------------------------------------------*/ +#if TRACELOG_CONF_NUM_ENTRIES > 0 +static void tracelog_snprint(char* buf, int bufsz, int i) +{ + struct tracelog_entry* trace = &tracelog.traces[i]; + int length = 0; + bufsz -= 1; // save one for zero + + #if (SYSLOG_CONF_LEVEL & SL_DEBUG) == SL_DEBUG + /* when running in debug level, event names are available and can be printed */ + char* name = (char*)string_table_get(symon_event_names, trace->event); + length = snprintf(buf, bufsz, "%#.2x (%s): ", trace->event, name); + #else + length = snprintf(buf, bufsz, "%#.2x: ", trace->event); + #endif + bufsz -= length; + buf += length; + + switch( trace->type ) { + case TRACE_NUMBER: { + tracelog_number_t uldata; + memcpy(&uldata, trace->data, sizeof(tracelog_number_t)); + length += snprintf(buf, bufsz, "%#10lx (%lu)", uldata, uldata); + break; + } + case TRACE_POINTER: { + void* uldata; + memcpy(&uldata, trace->data, sizeof(void*)); + length += snprintf(buf, bufsz, "%p", uldata); + break; + } + case TRACE_STRING: + length += snprintf(buf, bufsz, "%.*s", TRACELOG_CONF_ENTRY_SIZE, trace->data); + break; + default: + break; + } + buf[length] = '\0'; +} +#endif +/*-----------------------------------------------------------------------------------*/ +/** + * @brief Writes a new tracelog entry + * @internal + */ +static void +trace( + enum tracelog_event event, + const enum tracelog_type t, + const void (* const data), + const int size +) { +#if TRACELOG_CONF_NUM_ENTRIES > 0 + int length = size; + + if( tracelog_initialized == false ) + return; + + struct tracelog_entry* trace = &tracelog.traces[tracelog.tail]; // get current tail element + /* increase tail */ + if( (tracelog.tail + 1) < TRACELOG_CONF_NUM_ENTRIES ) + tracelog.tail++; + else + tracelog.tail = 0; + + /* fill meta data */ + trace->event = event & 0x7F; + trace->type = t; + + /* calculate size */ + if( length == 0 ) { + if( t == TRACE_STRING ) { + length = strlen((char*)data); + } + } + length = (TRACELOG_CONF_ENTRY_SIZE < length) ? TRACELOG_CONF_ENTRY_SIZE : length; + + memcpy( trace->data, data, length ); // copy description +#endif +} +/*-----------------------------------------------------------------------------------*/ +void trace_reset(void) +{ +#if TRACELOG_CONF_NUM_ENTRIES > 0 + #if SYSLOG_ISLEVEL(SL_DEBUG) + char buffer[12]; + sysmon_write_reset_info(buffer, 12, sysmon.reset_code); + trace_string(TRACELOG_EV_START, buffer); + #else + trace_number(TRACELOG_EV_START, sysmon.reset_code); + #endif +#endif +} +/*-----------------------------------------------------------------------------------*/ +void +tracelog_init(void) +{ +#if TRACELOG_CONF_NUM_ENTRIES > 0 + if( tracelog_initialized != 0 ) + return; + + if( sysmon_initial_boot() ) { + memset( &tracelog, 0, sizeof(struct tracelog) ); // clear tracelog buffer on initial boot only + } + + tracelog_initialized = true; // accept traces + + trace_reset(); // trace reason for last reset +#endif +} +void +tracelog_dump(void) +{ + printf("[trace] {\n"); +#if TRACELOG_CONF_NUM_ENTRIES > 0 + char buf[30 + TRACELOG_CONF_ENTRY_SIZE]; + int i = tracelog.tail; // tracelog tail holds next index + do { + i--; + if( i < 0 ) + i = TRACELOG_CONF_NUM_ENTRIES - 1; + tracelog_snprint(buf, sizeof(buf), i); + printf("\t %.2i: %s\n", i, buf); + } while( i != tracelog.tail ); +#endif + + printf("}\n"); +} +/*-----------------------------------------------------------------------------------*/ +void +trace_event(enum tracelog_event event) +{ +#if TRACELOG_CONF_NUM_ENTRIES > 0 + trace(event, TRACE_NULL, NULL, 0); +#endif +} +/*-----------------------------------------------------------------------------------*/ +void +trace_number(enum tracelog_event event, tracelog_number_t number) +{ +#if TRACELOG_CONF_NUM_ENTRIES > 0 + trace(event, TRACE_NUMBER, &number, sizeof(tracelog_number_t)); +#endif +} +/*-----------------------------------------------------------------------------------*/ +void +trace_pointer(enum tracelog_event event, void* pointer) +{ +#if TRACELOG_CONF_NUM_ENTRIES > 0 + trace(event, TRACE_POINTER, &pointer, sizeof(void*)); +#endif +} +/*-----------------------------------------------------------------------------------*/ +void +trace_string(enum tracelog_event event, char* string) +{ +#if TRACELOG_CONF_NUM_ENTRIES > 0 + trace(event, TRACE_STRING, string, strlen(string)); +#endif +} +/*-----------------------------------------------------------------------------------*/ +#if CMD_ISLEVEL(CMD_LEVEL_SYSTEM_DEBUG | CMD_LEVEL_HUMAN_USER) +/** + * @brief Trace command: trace [event] [string] + * @ingroup commands + * @param event Event to add to trace (optional) + * @param string String commend to include with event (optional) + * + * If no parameters are given dumps the current system event trace. + */ +ASCCMD(trace, CMDFLAG_SERIAL, "[event] [text]: print tracelog / trace event [num] with [text]"); +CMD_FUNCTION(trace, cmdargs) +{ +#if TRACELOG_CONF_NUM_ENTRIES > 0 + if( cmdargs->arg_size > 0 ) { + enum tracelog_event event; + char* c = (char*)cmdargs->args; + event = (enum tracelog_event)strtoul(c, &c, 0); // read event number + if( event > 0 ) { + c++; // skip expected whitespace + trace_string(event, c); // generate event with argument as text + return true; + } + } +#endif + tracelog_dump(); + + return CMD_SUCCESS; +} +#endif +/*-----------------------------------------------------------------------------------*/ +/** @} */ diff --git a/sys/transceiver/makefile b/sys/transceiver/makefile new file mode 100644 index 000000000..43efa202b --- /dev/null +++ b/sys/transceiver/makefile @@ -0,0 +1,6 @@ +INCLUDES = -I../include -I../drivers/include -I../drivers/cc110x_ng/include -I../lib -I../../cpu/$(CPU)/include -I../../cpu/ -I../net -I../../hal/include -I../../core/include -I../config +MODULE =transceiver + +include $(MAKEBASE)/makefile.base + + diff --git a/sys/transceiver.c b/sys/transceiver/transceiver.c similarity index 100% rename from sys/transceiver.c rename to sys/transceiver/transceiver.c diff --git a/sys/vtimer.c b/sys/vtimer.c index 9ca66adc6..4a88b128f 100644 --- a/sys/vtimer.c +++ b/sys/vtimer.c @@ -47,7 +47,7 @@ static int set_longterm(vtimer_t *timer) { return 0; } -static int update_shortterm() { +static int update_shortterm(void) { if (hwtimer_id != -1) { if (hwtimer_next_absolute != shortterm_queue_root.next->priority) { hwtimer_remove(hwtimer_id);