diff --git a/sys/include/ringbuffer.h b/sys/include/ringbuffer.h
index 97bccb554426f304877215b2dfdd554f31e22ea7..5819f2a15f294e8df2ae4a16c45f032a2b3a9173 100644
--- a/sys/include/ringbuffer.h
+++ b/sys/include/ringbuffer.h
@@ -12,24 +12,114 @@
  * @{
  * @file   ringbuffer.h
  * @author Kaspar Schleiser <kaspar@schleiser.de>
+ * @author René Kijewski <rene.kijewski@fu-berlin.de>
  * @}
  */
 
 #ifndef __RINGBUFFER_H
 #define __RINGBUFFER_H
 
+/**
+ * @brief     Ringbuffer.
+ * @details   Non thread-safe FIFO ringbuffer implementation around a `char` array.
+ */
 typedef struct ringbuffer {
-    char *buf;
-    unsigned int        start;
-    unsigned int        end;
-    unsigned int        size;
-    unsigned int        avail;
+    char *buf;          /**< Buffer to operate on. */
+    unsigned int size;  /**< Size of buf. */
+    unsigned int start; /**< Current read position in the ring buffer. */
+    unsigned int avail; /**< Number of elements available for reading. */
 } ringbuffer_t;
 
-void ringbuffer_init(ringbuffer_t *rb, char *buffer, unsigned int bufsize);
-void ringbuffer_add_one(ringbuffer_t *rb, char c);
-void ringbuffer_add(ringbuffer_t *rb, char *buf, int n);
-int ringbuffer_get_one(ringbuffer_t *rb);
-int ringbuffer_get(ringbuffer_t *rb, char *buf, int n);
+/**
+ * @def          RINGBUFFER_INIT(BUF)
+ * @brief        Initialize a ringbuffer.
+ * @details      This macro is meant for static ringbuffers.
+ * @param[in]    BUF   Buffer to use for the ringbuffer. The size is deduced through `sizeof (BUF)`.
+ * @returns      The static initializer.
+ */
+#define RINGBUFFER_INIT(BUF) { (BUF), sizeof (BUF), 0, 0 }
+
+/**
+ * @brief        Initialize a ringbuffer.
+ * @param[out]   rb        Datum to initialize.
+ * @param[in]    buffer    Buffer to use by rb.
+ * @param[in]    bufsize   `sizeof (buffer)`
+ */
+void ringbuffer_init(ringbuffer_t *restrict rb, char *buffer, unsigned bufsize);
+
+/**
+ * @brief           Add an element to the ringbuffer.
+ * @details         If rb is full, then the oldest element gets overwritten.
+ *                  Test ringbuffer_full() first if overwriting is not intended.
+ * @param[in,out]   rb   Ringbuffer to operate on.
+ * @param[in]       c    Element to add.
+ * @returns         The element that was dropped, iff the buffer was full.
+ *                  -1 iff the buffer was not full.
+ */
+int ringbuffer_add_one(ringbuffer_t *restrict rb, char c);
+
+/**
+ * @brief           Add a number of elements to the ringbuffer.
+ * @details         Only so many elements are added as fit in the ringbuffer.
+ *                  No elements get overwritten.
+ *                  If this is not the intended behavior, then use ringbuffer_add_one() in a loop instead.
+ * @param[in,out]   rb    Ringbuffer to operate on.
+ * @param[in]       buf   Buffer to add elements from.
+ * @param[in]       n     Maximum number of elements to add.
+ * @returns         Number of elements actually added. 0 if rb is full.
+ */
+unsigned ringbuffer_add(ringbuffer_t *restrict rb, const char *buf, unsigned n);
+
+/**
+ * @brief           Peek and remove oldest element from the ringbuffer.
+ * @param[in,out]   rb   Ringbuffer to operate on.
+ * @returns         The oldest element that was added, or `-1` if rb is empty.
+ */
+int ringbuffer_get_one(ringbuffer_t *restrict rb);
+
+/**
+ * @brief           Read and remove a number of elements from the ringbuffer.
+ * @param[in,out]   rb    Ringbuffer to operate on.
+ * @param[out]      buf   Buffer to write into.
+ * @param[in]       n     Read at most n elements.
+ * @returns         Number of elements actually read.
+ */
+unsigned ringbuffer_get(ringbuffer_t *restrict rb, char *buf, unsigned n);
+
+/**
+ * @brief           Test if the ringbuffer is empty.
+ * @param[in,out]   rb    Ringbuffer to operate on.
+ * @returns         0 iff not empty
+ */
+static inline int ringbuffer_empty(const ringbuffer_t *restrict rb)
+{
+    return rb->avail == 0;
+}
+
+/**
+ * @brief           Test if the ringbuffer is full.
+ * @param[in,out]   rb    Ringbuffer to operate on.
+ * @returns         0 iff not full
+ */
+static inline int ringbuffer_full(const ringbuffer_t *restrict rb)
+{
+    return rb->avail == rb->size;
+}
+
+/**
+ * @brief           Read, but don't remove, the oldest element in the buffer.
+ * @param[in]       rb    Ringbuffer to operate on.
+ * @returns         Same as ringbuffer_get_one()
+ */
+int ringbuffer_peek_one(const ringbuffer_t *restrict rb);
+
+/**
+ * @brief           Read, but don't remove, the a number of element of the buffer.
+ * @param[in]       rb    Ringbuffer to operate on.
+ * @param[out]      buf   Buffer to write into.
+ * @param[in]       n     Read at most n elements.
+ * @returns         Same as ringbuffer_get()
+ */
+unsigned ringbuffer_peek(const ringbuffer_t *restrict rb, char *buf, unsigned n);
 
 #endif /* __RINGBUFFER_H */
diff --git a/sys/lib/ringbuffer.c b/sys/lib/ringbuffer.c
index ea60f6b2a8b92ad0c671bf2d4e0fdbdfd1573d62..be2263a3296e5154aeee0c506adaf85cd6d22424 100644
--- a/sys/lib/ringbuffer.c
+++ b/sys/lib/ringbuffer.c
@@ -12,137 +12,104 @@
  * @{
  * @file   ringbuffer.c
  * @author Kaspar Schleiser <kaspar@schleiser.de>
+ * @author René Kijewski <rene.kijewski@fu-berlin.de>
  * @}
  */
 
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-
-#if (defined(__MACH__) || defined(__FreeBSD__))
-#include <stdlib.h>
-#else
-#include "malloc.h"
-#endif
-
-#define ENABLE_DEBUG (0)
-#include "debug.h"
-
 #include "ringbuffer.h"
 
-void ringbuffer_init(ringbuffer_t *rb, char *buffer, unsigned int bufsize)
+void ringbuffer_init(ringbuffer_t *restrict rb, char *buffer, unsigned bufsize)
 {
     rb->buf = buffer;
-    rb->start = 0;
-    rb->end = 0;
     rb->size = bufsize;
+    rb->start = 0;
     rb->avail = 0;
 }
 
-void ringbuffer_add(ringbuffer_t *rb, char *buf, int n)
+/**
+ * @brief           Add an element to the end of the ringbuffer.
+ * @details         This helper function does not check the pre-requirements for adding,
+ *                  i.e. the caller has to ensure that ringbuffer_full() is false.
+ * @param[in,out]   rb   Ringbuffer to operate on.
+ * @param[in]       c    Element to add.
+ */
+static void add_tail(ringbuffer_t *restrict rb, char c)
 {
-    for (int i = 0; i < n; i++) {
-        ringbuffer_add_one(rb, buf[i]);
+    unsigned pos = rb->start + rb->avail++;
+    if (pos >= rb->size) {
+        pos -= rb->size;
     }
+    rb->buf[pos] = c;
 }
 
-void ringbuffer_add_one(ringbuffer_t *rb, char c)
+/**
+ * @brief           Remove an element from the start of the ringbuffer.
+ * @details         This helper function does not check the pre-requirements for reading,
+ *                  i.e. the caller has to ensure that ringbuffer_empty() is false.
+ * @param[in,out]   rb   Ringbuffer to operate on.
+ * @returns         The removed element.
+ */
+static char get_head(ringbuffer_t *restrict rb)
 {
-    if (rb->avail == rb->size) {
-        ringbuffer_get_one(rb);
-    }
-
-    rb->buf[rb->end++] = c;
-
-    if (rb->end >= rb->size) {
-        rb->end = 0;
+    char result = rb->buf[rb->start];
+    if ((--rb->avail == 0) || (++rb->start == rb->size)) {
+        rb->start = 0;
     }
-
-    rb->avail++;
+    return result;
 }
 
-int ringbuffer_get_one(ringbuffer_t *rb)
+unsigned ringbuffer_add(ringbuffer_t *restrict rb, const char *buf, unsigned n)
 {
-    if (rb->avail == 0) {
-        return -1;
+    unsigned i;
+    for (i = 0; i < n; i++) {
+        if (ringbuffer_full(rb)) {
+            break;
+        }
+        add_tail(rb, buf[i]);
     }
+    return i;
+}
 
-    rb->avail--;
-
-    int c = (char)rb->buf[rb->start++];
-
-    if (rb->start >= rb->size) {
-        rb->start = 0;
+int ringbuffer_add_one(ringbuffer_t *restrict rb, char c)
+{
+    int result = -1;
+    if (ringbuffer_full(rb)) {
+        result = (unsigned char) get_head(rb);
     }
-
-    return c;
+    add_tail(rb, c);
+    return result;
 }
 
-int ringbuffer_get(ringbuffer_t *rb, char *buf, int n)
+int ringbuffer_get_one(ringbuffer_t *restrict rb)
 {
-    int count = 0;
-
-    while (rb->avail && (count < n)) {
-        buf[count++] = ringbuffer_get_one(rb);
+    if (!ringbuffer_empty(rb)) {
+        return (unsigned char) get_head(rb);
+    }
+    else {
+        return -1;
     }
-
-    return count;
 }
 
-/*
-int main(int argc, char *argv[] ){
-    ringbuffer r;
-    char buffer[5];
-    ringbuffer_init(&r, buffer, sizeof(buffer));
-
-    ringbuffer_add_one(&r, 1);
-    ringbuffer_add_one(&r, 2);
-    ringbuffer_add_one(&r, 3);
-    ringbuffer_add_one(&r, 4);
-    ringbuffer_add_one(&r, 5);
-    ringbuffer_add_one(&r, 6);
-    ringbuffer_add_one(&r, 7);
-    ringbuffer_add_one(&r, 8);
-    ringbuffer_add_one(&r, 9);
-    ringbuffer_add_one(&r, 10);
-
-    int c;
-    while ( r.avail ) {
-        c = ringbuffer_get_one(&r);
-        if (c == -1) break;
-        printf("c=%i\n", (int)c);
+unsigned ringbuffer_get(ringbuffer_t *restrict rb, char *buf, unsigned n)
+{
+    if (n > rb->avail) {
+        n = rb->avail;
     }
 
-    ringbuffer_add_one(&r, 1);
-    ringbuffer_add_one(&r, 2);
-    ringbuffer_add_one(&r, 3);
-    ringbuffer_add_one(&r, 4);
-    ringbuffer_add_one(&r, 5);
-
-    char buffer2[10];
-
-    int n = ringbuffer_get(&r, buffer2, sizeof(buffer2));
-
-    for (int i = 0; i < n; i++) {
-        printf("%i\n", buffer2[i]);
+    for (unsigned i = 0; i < n; ++i) {
+        buf[i] = get_head(rb);
     }
+    return n;
+}
 
-    ringbuffer_add_one(&r, 1);
-    ringbuffer_add_one(&r, 2);
-    ringbuffer_add_one(&r, 3);
-    ringbuffer_add_one(&r, 4);
-    ringbuffer_add_one(&r, 5);
-    ringbuffer_add_one(&r, 6);
-    ringbuffer_add_one(&r, 7);
-    ringbuffer_add_one(&r, 8);
-    ringbuffer_add_one(&r, 9);
-    ringbuffer_add_one(&r, 10);
-
-    while ( r.avail ) {
-        c = ringbuffer_get_one(&r);
-        if (c == -1) break;
-        printf("c=%i\n", (int)c);
-    }
+int ringbuffer_peek_one(const ringbuffer_t *restrict rb_)
+{
+    ringbuffer_t rb = *rb_;
+    return ringbuffer_get_one(&rb);
+}
 
-    return 0;
-}*/
+unsigned ringbuffer_peek(const ringbuffer_t *restrict rb_, char *buf, unsigned n)
+{
+    ringbuffer_t rb = *rb_;
+    return ringbuffer_get(&rb, buf, n);
+}
diff --git a/tests/unittests/tests-lib/Makefile b/tests/unittests/tests-lib/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2
--- /dev/null
+++ b/tests/unittests/tests-lib/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/tests/unittests/tests-lib/Makefile.include b/tests/unittests/tests-lib/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..6ba533d1b38f3aeb28242a6d8e962403dbae0c72
--- /dev/null
+++ b/tests/unittests/tests-lib/Makefile.include
@@ -0,0 +1 @@
+USEMODULE += lib
diff --git a/tests/unittests/tests-lib/tests-lib-ringbuffer.c b/tests/unittests/tests-lib/tests-lib-ringbuffer.c
new file mode 100644
index 0000000000000000000000000000000000000000..b4a42e28daaaa8126e7e3b20c74efe976ea82c27
--- /dev/null
+++ b/tests/unittests/tests-lib/tests-lib-ringbuffer.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2014  René Kijewski  <rene.kijewski@fu-berlin.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "thread.h"
+#include "flags.h"
+#include "kernel.h"
+#include "ringbuffer.h"
+#include "mutex.h"
+
+#include "tests-lib.h"
+
+/* (ITERATIONS * (BUF_SIZE + 1)) needs to be <= 127! Otherwise `char` overflows. */
+#define ITERATIONS 15
+#define BUF_SIZE 7
+
+static char stack_get[KERNEL_CONF_STACKSIZE_DEFAULT];
+
+static char rb_buf[BUF_SIZE];
+static ringbuffer_t rb = RINGBUFFER_INIT(rb_buf);
+static mutex_t mutex;
+static unsigned pid_add, pid_get;
+
+static void assert_avail(unsigned assumed)
+{
+    TEST_ASSERT_EQUAL_INT(assumed, rb.avail);
+}
+
+static void assert_add_one(char to_add, int assumed_result)
+{
+    int actual_result = ringbuffer_add_one(&rb, to_add);
+    TEST_ASSERT_EQUAL_INT(assumed_result, actual_result);
+}
+
+static void assert_get_one(int assumed_result)
+{
+    int actual_result = ringbuffer_get_one(&rb);
+    TEST_ASSERT_EQUAL_INT(assumed_result, actual_result);
+}
+
+static void run_add(void)
+{
+    char next = 0;
+    for (unsigned iteration = 0; iteration < ITERATIONS; ++iteration) {
+        mutex_lock(&mutex);
+
+        for (unsigned i = 0; i < BUF_SIZE; ++i) {
+            assert_avail(i);
+            assert_add_one(next, -1);
+            assert_avail(i + 1);
+            ++next;
+        }
+
+        /* Overwrite oldest element. It should be returned to us. */
+        assert_avail(BUF_SIZE);
+        assert_add_one(next, next - BUF_SIZE);
+        assert_avail(BUF_SIZE);
+        ++next;
+
+        thread_wakeup(pid_get);
+        mutex_unlock_and_sleep(&mutex);
+    }
+
+    thread_wakeup(pid_get);
+}
+
+static void *run_get(void *arg)
+{
+    (void) arg;
+
+    char next = 0;
+    for (unsigned iteration = 0; iteration < ITERATIONS; ++iteration) {
+        ++next; /* the first element of a stride is always overwritten */
+
+        mutex_lock(&mutex);
+
+        for (unsigned i = BUF_SIZE; i > 0; --i) {
+            assert_avail(i);
+            assert_get_one(next);
+            assert_avail(i - 1);
+            ++next;
+        }
+
+        assert_avail(0);
+        assert_get_one(-1);
+        assert_avail(0);
+
+        thread_wakeup(pid_add);
+        mutex_unlock_and_sleep(&mutex);
+    }
+
+    return NULL;
+}
+
+static void tests_lib_ringbuffer(void)
+{
+    pid_add = sched_active_pid;
+    pid_get = thread_create(stack_get, sizeof (stack_get),
+                            PRIORITY_MAIN, CREATE_SLEEPING | CREATE_STACKTEST,
+                            run_get, NULL, "get");
+    run_add();
+}
+
+Test *tests_lib_ringbuffer_tests(void)
+{
+    EMB_UNIT_TESTFIXTURES(fixtures) {
+        new_TestFixture(tests_lib_ringbuffer),
+    };
+
+    EMB_UNIT_TESTCALLER(ringbuffer_tests, NULL, NULL, fixtures);
+
+    return (Test *)&ringbuffer_tests;
+}
diff --git a/tests/unittests/tests-lib/tests-lib.c b/tests/unittests/tests-lib/tests-lib.c
new file mode 100644
index 0000000000000000000000000000000000000000..0fb20872a46b8e41ec22f12e48ed6f4fd163efd9
--- /dev/null
+++ b/tests/unittests/tests-lib/tests-lib.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2014 René Kijewski
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+#include "tests-lib.h"
+
+void tests_lib(void)
+{
+    TESTS_RUN(tests_lib_ringbuffer_tests());
+}
diff --git a/tests/unittests/tests-lib/tests-lib.h b/tests/unittests/tests-lib/tests-lib.h
new file mode 100644
index 0000000000000000000000000000000000000000..0644e49a42027741fa2aeec24f8aaeaee13c71de
--- /dev/null
+++ b/tests/unittests/tests-lib/tests-lib.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 René Kijewski
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @addtogroup  unittests
+ * @{
+ *
+ * @file        tests-lib.h
+ * @brief       Unittests for the ``lib`` sysmodule
+ *
+ * @author      Freie Universität Berlin, Computer Systems & Telematics
+ * @author      René Kijewski <rene.kijewski@fu-berlin.de>
+ */
+#ifndef __TESTS_CORE_H_
+#define __TESTS_CORE_H_
+
+#include "../unittests.h"
+
+/**
+ * @brief   The entry point of this test suite.
+ */
+void tests_lib(void);
+
+/**
+ * @brief   Generates tests ringbuffer.h
+ *
+ * @return  embUnit tests if successful, NULL if not.
+ */
+Test *tests_lib_ringbuffer_tests(void);
+
+#endif /* __TESTS_CORE_H_ */
+/** @} */