diff --git a/projects/test_shell/Jamfile b/projects/test_shell/Jamfile new file mode 100644 index 0000000000..f8d4b1d8b4 --- /dev/null +++ b/projects/test_shell/Jamfile @@ -0,0 +1,11 @@ +# +# FireKernel example project Jamfile +# +# Copyright (C) 2008, 2009 Kaspar Schleiser +# + +SubDir TOP projects test_shell ; + +Module test_shell : test_shell.c : shell ; + +UseModule test_shell ; diff --git a/projects/test_shell/test_shell.c b/projects/test_shell/test_shell.c new file mode 100644 index 0000000000..306c7f072f --- /dev/null +++ b/projects/test_shell/test_shell.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008, 2009, 2010 Kaspar Schleiser + */ + +#include +#include +#include + +#include + +void print_teststart(char* str) { + printf("[TEST_START]\n"); +} + +void print_testend(char* str) { + printf("[TEST_END]\n"); +} + +extern int uart0_init(); +extern int uart0_readc(); + +int main(void) { + //printf("Moin. build on %s %s SVN-Revision: %s\n", kernel_builddate, kernel_buildtime, kernel_svnrevision); + printf("test_shell.\n"); + + uart0_init(); + + shell_t shell; + shell_init(&shell, uart0_readc); + + shell_register_cmd(&shell, "start_test", print_teststart); + shell_register_cmd(&shell, "end_test", print_testend); + + shell_run(&shell); + + return 0; +} + + diff --git a/projects/test_shell/tests/01-basic b/projects/test_shell/tests/01-basic new file mode 100755 index 0000000000..23b25147cb --- /dev/null +++ b/projects/test_shell/tests/01-basic @@ -0,0 +1,30 @@ +#!/usr/bin/expect + +set timeout 5 + +spawn board/msba2/tools/bin/pseudoterm $env(PORT) + +expect { + ">$" {} + timeout { exit 1 } +} + +send "start_test\n" +expect { + "\[TEST_START\]" {} + timeout { exit 1 } +} + +expect { + ">$" {} + timeout { exit 1 } +} + +send "end_test\n" + +expect { + "\[TEST_END\]" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" diff --git a/projects/test_shell/tests/02-inputlength-regression b/projects/test_shell/tests/02-inputlength-regression new file mode 100755 index 0000000000..4ceb0f7934 --- /dev/null +++ b/projects/test_shell/tests/02-inputlength-regression @@ -0,0 +1,81 @@ +#!/usr/bin/expect + +set timeout 1 + +spawn board/msba2/tools/bin/pseudoterm $env(PORT) + +sleep 1 + +expect { + ">$" {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +send "123456789012345678901234567890123456789012345678901234567890\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + + +send "start_test\n" +expect { + "\[TEST_START\]" {} + timeout { exit 1 } +} + +expect { + ">$" {} + timeout { exit 1 } +} + +send "end_test\n" + +expect { + "\[TEST_END\]" {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" diff --git a/projects/test_shell/tests/02-unknown-command b/projects/test_shell/tests/02-unknown-command new file mode 100755 index 0000000000..bf0ed65a00 --- /dev/null +++ b/projects/test_shell/tests/02-unknown-command @@ -0,0 +1,20 @@ +#!/usr/bin/expect + +set timeout 1 + +spawn board/msba2/tools/bin/pseudoterm $env(PORT) + +sleep 1 + +expect { + ">$" {} + timeout { exit 1 } +} + +send "some_definately_unknown_command\n" +expect { + "shell: command not found." {} + timeout { exit 1 } +} + +puts "\nTest successful!\n" diff --git a/sys/include/shell.h b/sys/include/shell.h new file mode 100644 index 0000000000..e2527bcaba --- /dev/null +++ b/sys/include/shell.h @@ -0,0 +1,60 @@ +/****************************************************************************** +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 __SIMPLE_SHELL_H +#define __SIMPLE_SHELL_H + +/** + * @defgroup shell Simple Shell Interpreter + * @ingroup feuerware + */ + +#include "hashtable.h" + +typedef struct shell_t { + struct hashtable *h; + int (*readchar)(void); +} shell_t; + +/** + * @brief Initialize a shell object + */ +void shell_init(shell_t *shell, int(*readchar)(void)); + +/** + * @brief Register a new command handler for a shell. + * @param shell Shell object. + * @param name Name of the command to register. + * @param handler Function pointer to handler that takes the complete command line as parameter. + */ +void shell_register_cmd(shell_t *shell, char* name, void (*handler)(char* args)); + +/** + * @brief Endless loop that waits for command and executes handler. + */ +void shell_run(shell_t *shell); + +#endif /* __SIMPLE_SHELL_H */ diff --git a/sys/lib/Jamfile b/sys/lib/Jamfile new file mode 100644 index 0000000000..1158cdb7e4 --- /dev/null +++ b/sys/lib/Jamfile @@ -0,0 +1,10 @@ +# ****************************************************************************** +# Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved. +# ****************************************************************************** + +SubDir TOP sys lib ; + +Module hashtable : hashtable.c ; +Module hash_string : hash_string.c : hashtable ; +Module ringbuffer : ringbuffer.c ; + diff --git a/sys/lib/hash_string.c b/sys/lib/hash_string.c new file mode 100755 index 0000000000..a7611bcf6d --- /dev/null +++ b/sys/lib/hash_string.c @@ -0,0 +1,17 @@ +#include +#include "hash_string.h" + +unsigned long hash_string(unsigned char *str) +{ + unsigned long hash = 5381; + int c; + + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return hash; +} + +int cmp_string(char* a, char* b) { + return (strcmp(a,b) == 0); +} diff --git a/sys/lib/hash_string.h b/sys/lib/hash_string.h new file mode 100755 index 0000000000..a51c6abcc9 --- /dev/null +++ b/sys/lib/hash_string.h @@ -0,0 +1,7 @@ +#ifndef __HASH_STRING_H +#define __HASH_STRING_H + +unsigned long hash_string(unsigned char *str); +int cmp_string(char* a, char* b); + +#endif /* __HASH_STRING_H */ diff --git a/sys/lib/hashtable.c b/sys/lib/hashtable.c new file mode 100755 index 0000000000..763357edce --- /dev/null +++ b/sys/lib/hashtable.c @@ -0,0 +1,274 @@ +/* Copyright (C) 2004 Christopher Clark */ + +#include "hashtable.h" +#include "hashtable_private.h" +#include +#include +#include +#include + +/* +Credit for primes table: Aaron Krowne + http://br.endernet.org/~akrowne/ + http://planetmath.org/encyclopedia/GoodHashTablePrimes.html +*/ +static const unsigned int primes[] = { +53, 97, 193, 389, +769, 1543, 3079, 6151, +12289, 24593, 49157, 98317, +196613, 393241, 786433, 1572869, +3145739, 6291469, 12582917, 25165843, +50331653, 100663319, 201326611, 402653189, +805306457, 1610612741 +}; +const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]); +const float max_load_factor = 0.65; + +/*****************************************************************************/ +struct hashtable * +create_hashtable(unsigned int minsize, + unsigned int (*hashf) (void*), + int (*eqf) (void*,void*)) +{ + struct hashtable *h; + unsigned int pindex, size = primes[0]; + /* Check requested hashtable isn't too large */ + if (minsize > (1u << 30)) return NULL; + /* Enforce size as prime */ + for (pindex=0; pindex < prime_table_length; pindex++) { + if (primes[pindex] > minsize) { size = primes[pindex]; break; } + } + h = (struct hashtable *)malloc(sizeof(struct hashtable)); + if (NULL == h) return NULL; /*oom*/ + h->table = (struct entry **)malloc(sizeof(struct entry*) * size); + if (NULL == h->table) { free(h); return NULL; } /*oom*/ + memset(h->table, 0, size * sizeof(struct entry *)); + h->tablelength = size; + h->primeindex = pindex; + h->entrycount = 0; + h->hashfn = hashf; + h->eqfn = eqf; + h->loadlimit = (unsigned int) ceil(size * max_load_factor); + return h; +} + +/*****************************************************************************/ +unsigned int +hash(struct hashtable *h, void *k) +{ + /* Aim to protect against poor hash functions by adding logic here + * - logic taken from java 1.4 hashtable source */ + unsigned int i = h->hashfn(k); + i += ~(i << 9); + i ^= ((i >> 14) | (i << 18)); /* >>> */ + i += (i << 4); + i ^= ((i >> 10) | (i << 22)); /* >>> */ + return i; +} + +/*****************************************************************************/ +static int +hashtable_expand(struct hashtable *h) +{ + /* Double the size of the table to accomodate more entries */ + struct entry **newtable; + struct entry *e; + struct entry **pE; + unsigned int newsize, i, index; + /* Check we're not hitting max capacity */ + if (h->primeindex == (prime_table_length - 1)) return 0; + newsize = primes[++(h->primeindex)]; + + newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize); + if (NULL != newtable) + { + memset(newtable, 0, newsize * sizeof(struct entry *)); + /* This algorithm is not 'stable'. ie. it reverses the list + * when it transfers entries between the tables */ + for (i = 0; i < h->tablelength; i++) { + while (NULL != (e = h->table[i])) { + h->table[i] = e->next; + index = indexFor(newsize,e->h); + e->next = newtable[index]; + newtable[index] = e; + } + } + free(h->table); + h->table = newtable; + } + /* Plan B: realloc instead */ + else + { + newtable = (struct entry **) + realloc(h->table, newsize * sizeof(struct entry *)); + if (NULL == newtable) { (h->primeindex)--; return 0; } + h->table = newtable; + memset(newtable[h->tablelength], 0, newsize - h->tablelength); + for (i = 0; i < h->tablelength; i++) { + for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) { + index = indexFor(newsize,e->h); + if (index == i) + { + pE = &(e->next); + } + else + { + *pE = e->next; + e->next = newtable[index]; + newtable[index] = e; + } + } + } + } + h->tablelength = newsize; + h->loadlimit = (unsigned int) ceil(newsize * max_load_factor); + return -1; +} + +/*****************************************************************************/ +unsigned int +hashtable_count(struct hashtable *h) +{ + return h->entrycount; +} + +/*****************************************************************************/ +int +hashtable_insert(struct hashtable *h, void *k, void *v) +{ + /* This method allows duplicate keys - but they shouldn't be used */ + unsigned int index; + struct entry *e; + if (++(h->entrycount) > h->loadlimit) + { + /* Ignore the return value. If expand fails, we should + * still try cramming just this value into the existing table + * -- we may not have memory for a larger table, but one more + * element may be ok. Next time we insert, we'll try expanding again.*/ + hashtable_expand(h); + } + e = (struct entry *)malloc(sizeof(struct entry)); + if (NULL == e) { --(h->entrycount); return 0; } /*oom*/ + e->h = hash(h,k); + index = indexFor(h->tablelength,e->h); + e->k = k; + e->v = v; + e->next = h->table[index]; + h->table[index] = e; + return -1; +} + +/*****************************************************************************/ +void * /* returns value associated with key */ +hashtable_search(struct hashtable *h, void *k) +{ + struct entry *e; + unsigned int hashvalue, index; + hashvalue = hash(h,k); + index = indexFor(h->tablelength,hashvalue); + e = h->table[index]; + while (NULL != e) + { + /* Check hash value to short circuit heavier comparison */ + if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v; + e = e->next; + } + return NULL; +} + +/*****************************************************************************/ +void * /* returns value associated with key */ +hashtable_remove(struct hashtable *h, void *k) +{ + /* TODO: consider compacting the table when the load factor drops enough, + * or provide a 'compact' method. */ + + struct entry *e; + struct entry **pE; + void *v; + unsigned int hashvalue, index; + + hashvalue = hash(h,k); + index = indexFor(h->tablelength,hash(h,k)); + pE = &(h->table[index]); + e = *pE; + while (NULL != e) + { + /* Check hash value to short circuit heavier comparison */ + if ((hashvalue == e->h) && (h->eqfn(k, e->k))) + { + *pE = e->next; + h->entrycount--; + v = e->v; + freekey(e->k); + free(e); + return v; + } + pE = &(e->next); + e = e->next; + } + return NULL; +} + +/*****************************************************************************/ +/* destroy */ +void +hashtable_destroy(struct hashtable *h, int free_values) +{ + unsigned int i; + struct entry *e, *f; + struct entry **table = h->table; + if (free_values) + { + for (i = 0; i < h->tablelength; i++) + { + e = table[i]; + while (NULL != e) + { f = e; e = e->next; freekey(f->k); free(f->v); free(f); } + } + } + else + { + for (i = 0; i < h->tablelength; i++) + { + e = table[i]; + while (NULL != e) + { f = e; e = e->next; freekey(f->k); free(f); } + } + } + free(h->table); + free(h); +} + +/* + * Copyright (c) 2002, Christopher Clark + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff --git a/sys/lib/hashtable.h b/sys/lib/hashtable.h new file mode 100755 index 0000000000..b90781abd4 --- /dev/null +++ b/sys/lib/hashtable.h @@ -0,0 +1,199 @@ +/* Copyright (C) 2002 Christopher Clark */ + +#ifndef __HASHTABLE_CWC22_H__ +#define __HASHTABLE_CWC22_H__ + +struct hashtable; + +/* Example of use: + * + * struct hashtable *h; + * struct some_key *k; + * struct some_value *v; + * + * static unsigned int hash_from_key_fn( void *k ); + * static int keys_equal_fn ( void *key1, void *key2 ); + * + * h = create_hashtable(16, hash_from_key_fn, keys_equal_fn); + * k = (struct some_key *) malloc(sizeof(struct some_key)); + * v = (struct some_value *) malloc(sizeof(struct some_value)); + * + * (initialise k and v to suitable values) + * + * if (! hashtable_insert(h,k,v) ) + * { exit(-1); } + * + * if (NULL == (found = hashtable_search(h,k) )) + * { printf("not found!"); } + * + * if (NULL == (found = hashtable_remove(h,k) )) + * { printf("Not found\n"); } + * + */ + +/* Macros may be used to define type-safe(r) hashtable access functions, with + * methods specialized to take known key and value types as parameters. + * + * Example: + * + * Insert this at the start of your file: + * + * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value); + * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value); + * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value); + * + * This defines the functions 'insert_some', 'search_some' and 'remove_some'. + * These operate just like hashtable_insert etc., with the same parameters, + * but their function signatures have 'struct some_key *' rather than + * 'void *', and hence can generate compile time errors if your program is + * supplying incorrect data as a key (and similarly for value). + * + * Note that the hash and key equality functions passed to create_hashtable + * still take 'void *' parameters instead of 'some key *'. This shouldn't be + * a difficult issue as they're only defined and passed once, and the other + * functions will ensure that only valid keys are supplied to them. + * + * The cost for this checking is increased code size and runtime overhead + * - if performance is important, it may be worth switching back to the + * unsafe methods once your program has been debugged with the safe methods. + * This just requires switching to some simple alternative defines - eg: + * #define insert_some hashtable_insert + * + */ + +/***************************************************************************** + * create_hashtable + + * @name create_hashtable + * @param minsize minimum initial size of hashtable + * @param hashfunction function for hashing keys + * @param key_eq_fn function for determining key equality + * @return newly created hashtable or NULL on failure + */ + +struct hashtable * +create_hashtable(unsigned int minsize, + unsigned int (*hashfunction) (void*), + int (*key_eq_fn) (void*,void*)); + +/***************************************************************************** + * hashtable_insert + + * @name hashtable_insert + * @param h the hashtable to insert into + * @param k the key - hashtable claims ownership and will free on removal + * @param v the value - does not claim ownership + * @return non-zero for successful insertion + * + * This function will cause the table to expand if the insertion would take + * the ratio of entries to table size over the maximum load factor. + * + * This function does not check for repeated insertions with a duplicate key. + * The value returned when using a duplicate key is undefined -- when + * the hashtable changes size, the order of retrieval of duplicate key + * entries is reversed. + * If in doubt, remove before insert. + */ + +int +hashtable_insert(struct hashtable *h, void *k, void *v); + +#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \ +int fnname (struct hashtable *h, keytype *k, valuetype *v) \ +{ \ + return hashtable_insert(h,k,v); \ +} + +/***************************************************************************** + * hashtable_search + + * @name hashtable_search + * @param h the hashtable to search + * @param k the key to search for - does not claim ownership + * @return the value associated with the key, or NULL if none found + */ + +void * +hashtable_search(struct hashtable *h, void *k); + +#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \ +valuetype * fnname (struct hashtable *h, keytype *k) \ +{ \ + return (valuetype *) (hashtable_search(h,k)); \ +} + +/***************************************************************************** + * hashtable_remove + + * @name hashtable_remove + * @param h the hashtable to remove the item from + * @param k the key to search for - does not claim ownership + * @return the value associated with the key, or NULL if none found + */ + +void * /* returns value */ +hashtable_remove(struct hashtable *h, void *k); + +#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \ +valuetype * fnname (struct hashtable *h, keytype *k) \ +{ \ + return (valuetype *) (hashtable_remove(h,k)); \ +} + + +/***************************************************************************** + * hashtable_count + + * @name hashtable_count + * @param h the hashtable + * @return the number of items stored in the hashtable + */ +unsigned int +hashtable_count(struct hashtable *h); + + +/***************************************************************************** + * hashtable_destroy + + * @name hashtable_destroy + * @param h the hashtable + * @param free_values whether to call 'free' on the remaining values + */ + +void +hashtable_destroy(struct hashtable *h, int free_values); + +#endif /* __HASHTABLE_CWC22_H__ */ + +/* + * Copyright (c) 2002, Christopher Clark + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff --git a/sys/lib/hashtable_private.h b/sys/lib/hashtable_private.h new file mode 100755 index 0000000000..3e95f60057 --- /dev/null +++ b/sys/lib/hashtable_private.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2002, 2004 Christopher Clark */ + +#ifndef __HASHTABLE_PRIVATE_CWC22_H__ +#define __HASHTABLE_PRIVATE_CWC22_H__ + +#include "hashtable.h" + +/*****************************************************************************/ +struct entry +{ + void *k, *v; + unsigned int h; + struct entry *next; +}; + +struct hashtable { + unsigned int tablelength; + struct entry **table; + unsigned int entrycount; + unsigned int loadlimit; + unsigned int primeindex; + unsigned int (*hashfn) (void *k); + int (*eqfn) (void *k1, void *k2); +}; + +/*****************************************************************************/ +unsigned int +hash(struct hashtable *h, void *k); + +/*****************************************************************************/ +/* indexFor */ +static inline unsigned int +indexFor(unsigned int tablelength, unsigned int hashvalue) { + return (hashvalue % tablelength); +}; + +/* Only works if tablelength == 2^N */ +/*static inline unsigned int +indexFor(unsigned int tablelength, unsigned int hashvalue) +{ + return (hashvalue & (tablelength - 1u)); +} +*/ + +/*****************************************************************************/ +#define freekey(X) free(X) +/*define freekey(X) ; */ + + +/*****************************************************************************/ + +#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/ + +/* + * Copyright (c) 2002, Christopher Clark + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff --git a/sys/lib/ringbuffer.c b/sys/lib/ringbuffer.c new file mode 100755 index 0000000000..7975eb5a01 --- /dev/null +++ b/sys/lib/ringbuffer.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +#include "ringbuffer.h" + +//#define DEBUG(...) printf (__VA_ARGS__) +#define DEBUG(...) + +void ringbuffer_init(ringbuffer *rb, char* buffer, unsigned int bufsize) { + rb->buf = buffer; + rb->start = 0; + rb->end = 0; + rb->size = bufsize; + rb->avail = 0; +} + +void rb_add_element(ringbuffer* rb, char c) { + rb->buf[rb->end++] = c; + rb->avail++; + + if (rb->end >= rb->size) rb->end = 0; + if (rb->end == rb->start) rb->start++; + if (rb->start >= rb->size) rb->start = 0; +} + +int rb_get_element(ringbuffer *rb) { + if (rb->avail == 0) return -1; + + rb->avail--; + + int c = (char)rb->buf[rb->start++]; + + if (rb->start >= rb->size) rb->start = 0; + return c; +} + +int rb_get_elements(ringbuffer *rb, char* buf, int n) { + int count = 0; + while (rb->avail > 0) { + rb->avail--; + *buf++ = rb->buf[rb->start++]; + count++; + if (rb->start >= rb->size) rb->start = 0; + } + return count; +} + +/*int main(int argc, char *argv[] ){ + ringbuffer r; + char buffer[100]; + ringbuffer_init(&r, buffer, sizeof(buffer)); + + rb_add_element(&r, 'a'); + rb_add_element(&r, 'b'); + rb_add_element(&r, 'c'); + rb_add_element(&r, 'd'); + rb_add_element(&r, 'f'); + rb_add_element(&r, 'g'); + rb_add_element(&r, 'h'); + rb_add_element(&r, 'i'); + rb_add_element(&r, 'j'); + rb_add_element(&r, 'k'); + + int c; + while ( 1 ) { + c = rb_get_element(&r); + if (c == -1) break; + printf("c=%i\n", (int)c); + rb_add_element(&r, c); + } + + return 0; +}*/ diff --git a/sys/lib/ringbuffer.h b/sys/lib/ringbuffer.h new file mode 100755 index 0000000000..27966f5a94 --- /dev/null +++ b/sys/lib/ringbuffer.h @@ -0,0 +1,16 @@ +#ifndef __RINGBUFFER_H +#define __RINGBUFFER_H + +typedef struct ringbuffer { + char* buf; + unsigned int start; + unsigned int end; + unsigned int size; + unsigned int avail; +} ringbuffer; + +void ringbuffer_init(ringbuffer *rb, char* buffer, unsigned int bufsize); +void rb_add_element(ringbuffer* rb, char c); +int rb_get_element(ringbuffer *rb); + +#endif /* __RINGBUFFER_H */ diff --git a/sys/shell.c b/sys/shell.c new file mode 100644 index 0000000000..7ccd39a484 --- /dev/null +++ b/sys/shell.c @@ -0,0 +1,116 @@ +/****************************************************************************** +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 +*******************************************************************************/ + +/** + * @ingroup shell + * @{ + */ + +/** + * @file + * @brief Implementation of a very simple command interpreter. + * For each command (i.e. "echo"), a handler can be specified. + * If the first word of a user-entered command line matches the + * name of a handler, the handler will be called with the whole + * command line as parameter. + * + * @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project + * @author Kaspar Schleiser + * @version 2.0 $Revision$ + * + * @note $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include + +static void handle_input_line(shell_t *shell, char* line) { + char* saveptr; + char* command = strtok_r(line, " ", &saveptr); + + void (*handler)(char*) = NULL; + + if (command) { + handler = hashtable_search(shell->h, command); + if (handler) { + handler(line); + } else { + printf("shell: command not found.\n"); + } + } + + free(line); +} + +void shell_run(shell_t *shell) { + char line_buf[255]; + char *line_buf_ptr = line_buf; + int c; + + while(1) { + write(STDOUT_FILENO, ">", 1); + + while (1) { + if ( (line_buf_ptr - line_buf) >= (sizeof(line_buf)-1)) { + printf("\nshell: input too long.\n"); + line_buf_ptr = line_buf; + } + + c = shell->readchar(); + + write(STDOUT_FILENO, &c, 1); + + if (c == 13) continue; + + if (c == 10) { + *line_buf_ptr = '\0'; + handle_input_line(shell, strdup(line_buf)); + line_buf_ptr = line_buf; + break; + } else { + *line_buf_ptr++ = c; + } + } + } +} + +void shell_init(shell_t *shell, int(*readchar)(void)) { + shell->h = create_hashtable(16, (unsigned int (*)(void*)) hash_string, (int (*) (void*,void*)) cmp_string); + shell->readchar = readchar; +} + +void shell_register_cmd(shell_t *shell, char* name, void (*handler)(char* args)) { + hashtable_insert(shell->h, name, handler); +} + +/** + * @} + */ diff --git a/sys/sync_read.c b/sys/sync_read.c new file mode 100644 index 0000000000..d4e89ab7b9 --- /dev/null +++ b/sys/sync_read.c @@ -0,0 +1,98 @@ +/****************************************************************************** +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 +#include +#include + +/** + * @file + * @ingroup simple_shell + * @brief contains implementation of synchronous read functions, + * @brief hardcoded to uart0 + * @author Kaspar Schleiser + * + */ + +extern void (*uart0_callback)(int); + +#define UART0_BUFSIZE 255 +static ringbuffer uart0_rb; +static char uart0_buffer[UART0_BUFSIZE]; +static char uart0_waiting = 0; + +static mutex_t uart0_mutex; + +void uart0_process_byte(int c) { + rb_add_element(&uart0_rb, c); + + if (uart0_waiting) { + uart0_waiting = 0; + mutex_unlock(&uart0_mutex, false); + } +} + +void uart0_init() { + dINT(); + mutex_init(&uart0_mutex); + mutex_lock(&uart0_mutex); + ringbuffer_init(&uart0_rb, uart0_buffer, UART0_BUFSIZE); + uart0_callback = uart0_process_byte; + eINT(); +} + +/** @brief read a char from uart0. Block if none available. */ +int uart0_readc() { + dINT(); + + if (uart0_rb.avail == 0) { + uart0_waiting++; + mutex_lock(&uart0_mutex); + } + + int c = rb_get_element(&uart0_rb); + + eINT(); + + return c; +} + +/** @brief read a char from uart0. return -1 if none available */ +int uart0_readc_nb() { + dINT(); + + if (uart0_rb.avail == 0) { + eINT(); + return -1; + } + + int c = rb_get_element(&uart0_rb); + + eINT(); + + return c; +} +