From 321cc67d890042025625df6a591fcfe9e62ec95d Mon Sep 17 00:00:00 2001
From: Oscar Olsson <osse.olsson@gmail.com>
Date: Tue, 5 Mar 2013 13:00:23 +0100
Subject: [PATCH] Added changes from firefly

---
 compiler/build.xml                            |   4 +-
 lib/c/Makefile                                |  81 +++++++-
 lib/c/cppmacros.h                             |   8 +
 lib/c/experimental/ThrottleDrv/display.h      |   7 +-
 lib/c/experimental/ThrottleDrv/ethernet_drv.c |   5 +-
 lib/c/experimental/ethaddr.c                  |   6 +-
 lib/c/experimental/udp_hack.c                 |   6 +-
 lib/c/labcomm.c                               | 176 ++++++++++++++---
 lib/c/labcomm.h                               |  75 ++++++-
 lib/c/labcomm_mem_reader.c                    |  73 +++++++
 lib/c/labcomm_mem_reader.h                    |  17 ++
 lib/c/labcomm_mem_writer.c                    | 143 ++++++++++++++
 lib/c/labcomm_mem_writer.h                    |  25 +++
 lib/c/labcomm_private.h                       |  18 +-
 lib/c/test/test_labcomm.c                     | 187 ++++++++++++++++++
 lib/c/test/test_labcomm_errors                | Bin 0 -> 46272 bytes
 lib/c/test/test_labcomm_errors.c              | 168 ++++++++++++++++
 lib/c/test/test_labcomm_errors.h              |   6 +
 lib/c/test/testdata/test_sample.lc            |   1 +
 19 files changed, 957 insertions(+), 49 deletions(-)
 create mode 100644 lib/c/cppmacros.h
 create mode 100644 lib/c/labcomm_mem_reader.c
 create mode 100644 lib/c/labcomm_mem_reader.h
 create mode 100644 lib/c/labcomm_mem_writer.c
 create mode 100644 lib/c/labcomm_mem_writer.h
 create mode 100644 lib/c/test/test_labcomm.c
 create mode 100755 lib/c/test/test_labcomm_errors
 create mode 100644 lib/c/test/test_labcomm_errors.c
 create mode 100644 lib/c/test/test_labcomm_errors.h
 create mode 100644 lib/c/test/testdata/test_sample.lc

diff --git a/compiler/build.xml b/compiler/build.xml
index 932ba04..ff8cf2a 100644
--- a/compiler/build.xml
+++ b/compiler/build.xml
@@ -4,7 +4,7 @@
        clean           - removes all generated files and class files
  Targets for working from Eclipse:
        gen             - generates java files
-       genClean        - removes all generated files and their class files
+       cleanGen        - removes all generated files and their class files
 -->
 <project name="LabComm" default="build" basedir=".">
 
@@ -77,7 +77,9 @@ classpath="tools/jastadd2.jar"/>
      <!-- delete all .class files recursively -->
     <delete>
       <fileset dir="." includes="**/*.class"/>
+      <fileset dir="." includes="labComm.jar"/>
     </delete>
+
 </target>
 
 
diff --git a/lib/c/Makefile b/lib/c/Makefile
index 4d7117e..a17c72d 100644
--- a/lib/c/Makefile
+++ b/lib/c/Makefile
@@ -1,22 +1,85 @@
-CC = gcc
-CFLAGS = -g -I .
+## Macros
 
-liblabcomm.a : labcomm.o labcomm_fd_reader_writer.o experimental/labcomm_udp_reader_writer.o \
-               experimental/udp_hack.o experimental/ethaddr.o \
-               experimental/labcomm_thr_reader_writer.o \
-               experimental/ThrottleDrv/ethernet_drv.o experimental/ThrottleDrv/throttle_drv.o
+# Use LLVM clang if it's found.
+CC = $(shell hash clang 2>/dev/null && echo clang || echo gcc)
+CFLAGS = -g -Wall -I .
+LDFLAGS = -L .
+LDLIBS_TEST = -lcunit -llabcomm
+
+OBJS= labcomm.o labcomm_fd_reader_writer.o labcomm_mem_reader.o labcomm_mem_writer.o
+LABCOMMC_PATH=../../compiler
+LABCOMMC_JAR=$(LABCOMMC_PATH)/labComm.jar
+
+TEST_DIR=test
+TESTDATA_DIR=$(TEST_DIR)/testdata
+TEST_GEN_DIR=$(TESTDATA_DIR)/gen
+
+CREATED_DIRS=$(TEST_DIR) $(TESTDATA_DIR) $(TEST_GEN_DIR)
+
+# Disable experimental objects by invoking make like `make -e LABCOMM_NO_EXPERIMENTAL=true`
+ifneq ($(LABCOMM_NO_EXPERIMENTAL),true)
+	OBJS += experimental/udp_hack.o experimental/ethaddr.o \
+		experimental/labcomm_thr_reader_writer.o \
+		experimental/ThrottleDrv/ethernet_drv.o \
+		experimental/ThrottleDrv/throttle_drv.o \
+		experimental/labcomm_udp_reader_writer.o
+endif
+
+## Targets
+
+.PHONY: all run-test clean distclean
+
+all: liblabcomm.a test/test_labcomm_errors
+
+liblabcomm.a: $(OBJS)
 	ar -r liblabcomm.a $^
 
+
 labcomm.o : labcomm.c labcomm.h  labcomm_private.h
 
 labcomm_fd_reader_writer.o : labcomm_fd_reader_writer.c  labcomm_fd_reader_writer.h  labcomm.h  labcomm_private.h
 
+labcomm_mem_reader.o: labcomm_fd_reader_writer.c labcomm_fd_reader_writer.h
+
+labcomm_mem_writer.o: labcomm_mem_writer.c labcomm_mem_writer.h cppmacros.h
+
 ethaddr.o: ethaddr.c
 
-%o: %c %h
+$(CREATED_DIRS):
+	mkdir -p $@
+
+run-test: $(TEST_DIR)/test_labcomm_errors |$(TEST_DIR)
+	test/test_labcomm_errors
+
+$(TEST_DIR)/test_labcomm_errors: $(TEST_DIR)/test_labcomm_errors.o liblabcomm.a |$(TEST_DIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) -llabcomm -o $@ $^
+
+$(TEST_DIR)/test_labcomm_errors.o: $(TEST_DIR)/test_labcomm_errors.c $(TEST_DIR)/test_labcomm_errors.h |$(TEST_DIR)
+	cd test; $(CC) $(CFLAGS) -I .. -c $(patsubst $(TEST_DIR)/%, %, $^)
+
+$(TEST_DIR)/test_labcomm.o: $(TEST_DIR)/test_labcomm.c $(TEST_GEN_DIR)/test_sample.h |$(TEST_DIR)
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+$(TEST_DIR)/test_labcomm: $(TEST_DIR)/test_labcomm.o $(TEST_GEN_DIR)/test_sample.o liblabcomm.a
+	$(CC) $(CFLAGS) $(LDFLAGS) $(filter-out %.a,$^) $(LDLIBS) $(LDLIBS_TEST) -o $@
+
+$(TEST_GEN_DIR)/%.c $(TEST_GEN_DIR)/%.h: $(TESTDATA_DIR)/%.lc $(LABCOMMC_JAR) |$(TEST_GEN_DIR)
+	java -jar $(LABCOMMC_JAR) --c=$(patsubst %.h,%.c,$@) --h=$(patsubst %.c,%.h,$@) $<
+
+$(LABCOMMC_JAR):
+	@echo "======Building LabComm compiler======"
+	cd $(LABCOMMC_PATH); ant jar
+	@echo "======End building LabComm compiler======"
+
+%.o: %.c %.h
 
 clean:
-	rm *.o experimental/*.o experimental/ThrottleDrv/*.o
+	$(RM) *.o
+	$(RM) experimental/*.o experimental/ThrottleDrv/*.o
+	$(RM) test/*.o
+	$(RM) test/*.gch
+	$(RM) test/test_labcomm_errors
+	$(RM) $(TEST_DIR)/test_labcomm
 
 distclean: clean
-	rm liblabcomm.a
+	$(RM) liblabcomm.a
diff --git a/lib/c/cppmacros.h b/lib/c/cppmacros.h
new file mode 100644
index 0000000..a3e446b
--- /dev/null
+++ b/lib/c/cppmacros.h
@@ -0,0 +1,8 @@
+// C Preprocessor macros.
+#ifndef CPP_MACROS_H
+#define CPP_MACROS_H
+
+#define X_EMPTY(mac) var ## 1
+#define EMPTY(mac) X_EMPTY(mac)	// Returns 1 if macro mac is empty.
+
+#endif
diff --git a/lib/c/experimental/ThrottleDrv/display.h b/lib/c/experimental/ThrottleDrv/display.h
index f8bed75..49c9cd4 100644
--- a/lib/c/experimental/ThrottleDrv/display.h
+++ b/lib/c/experimental/ThrottleDrv/display.h
@@ -1,7 +1,12 @@
 #define PC_MODE
 #ifdef PC_MODE
-#include <stdio.h>
 #define DISPLAY_ERR(s) 	perror(s);
+
+// Some projects can not use stdio.h.
+#ifndef LABCOMM_NO_STDIO
+  #include <stdio.h>
+#endif
+
 #else
 #define DISPLAY_ERR(s)  ;
 #endif
diff --git a/lib/c/experimental/ThrottleDrv/ethernet_drv.c b/lib/c/experimental/ThrottleDrv/ethernet_drv.c
index fe0004c..9b4126e 100644
--- a/lib/c/experimental/ThrottleDrv/ethernet_drv.c
+++ b/lib/c/experimental/ThrottleDrv/ethernet_drv.c
@@ -1,7 +1,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <stdio.h>
 #include <errno.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
@@ -14,6 +13,10 @@
 #include "ethernet_drv.h"
 #include "display.h"
 
+// Some projects can not use stdio.h.
+#ifndef LABCOMM_NO_STDIO
+  #include <stdio.h>
+#endif
 
 /** LOCAL FUNCTIONS **/
 
diff --git a/lib/c/experimental/ethaddr.c b/lib/c/experimental/ethaddr.c
index b2207e5..5aed408 100644
--- a/lib/c/experimental/ethaddr.c
+++ b/lib/c/experimental/ethaddr.c
@@ -1,6 +1,10 @@
-#include <stdio.h>
 #include "ethaddr.h"
 
+// Some projects can not use stdio.h.
+#ifndef LABCOMM_NO_STDIO
+  #include <stdio.h>
+#endif
+
 #if ETH_ALEN != 6 
 	#warning "Assumption that ETH_ALEN == 6 appears false. Here be dragons."
 #endif
diff --git a/lib/c/experimental/udp_hack.c b/lib/c/experimental/udp_hack.c
index f4670bb..1d26eb7 100644
--- a/lib/c/experimental/udp_hack.c
+++ b/lib/c/experimental/udp_hack.c
@@ -1,11 +1,15 @@
 #include <arpa/inet.h>
 #include <netinet/in.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <unistd.h>
 
+// Some projects can not use stdio.h.
+#ifndef LABCOMM_NO_STDIO
+  #include <stdio.h>
+#endif
+
 #define BUFLEN 512
 #define NPACK 10
 #define PORT 9930
diff --git a/lib/c/labcomm.c b/lib/c/labcomm.c
index 34ce50b..76324da 100644
--- a/lib/c/labcomm.c
+++ b/lib/c/labcomm.c
@@ -1,18 +1,32 @@
 #include <errno.h>
 #include <string.h>
-#include <stdio.h>
+
 #ifndef __VXWORKS__
-#include <strings.h>
+  #ifdef ARM_CORTEXM3_CODESOURCERY
+    #include <string.h>
+  #else
+    #include <strings.h>
+  #endif
 #endif
-#include <stdlib.h>
-#ifdef __VXWORKS__
-#if (CPU == PPC603)
-#undef _LITTLE_ENDIAN
+
+#ifndef ARM_CORTEXM3_CODESOURCERY
+  #include <stdlib.h>
 #endif
-#if (CPU == PENTIUM4)
-#undef _BIG_ENDIAN
+
+// Some projects can not use stdio.h.
+#ifndef LABCOMM_NO_STDIO
+  #include <stdio.h>
 #endif
+
+#ifdef __VXWORKS__
+  #if (CPU == PPC603)
+    #undef _LITTLE_ENDIAN
+  #endif
+  #if (CPU == PENTIUM4)
+    #undef _BIG_ENDIAN
+  #endif
 #endif
+
 #include "labcomm.h"
 #include "labcomm_private.h"
 
@@ -35,6 +49,83 @@ typedef struct labcomm_decoder_context {
   labcomm_sample_entry_t *sample;
 } labcomm_decoder_context_t;
 
+void labcomm_register_error_handler_encoder(struct labcomm_encoder *encoder, labcomm_error_handler_callback callback)
+{
+ encoder->on_error = callback; 
+ encoder->writer.on_error = callback; 
+}
+
+void labcomm_register_error_handler_decoder(struct labcomm_decoder *decoder, labcomm_error_handler_callback callback)
+{
+ decoder->on_error = callback; 
+ decoder->reader.on_error = callback; 
+}
+
+/* Error strings. _must_ be the same order as in enum labcomm_error */
+const char *labcomm_error_strings[] = { 
+  "Enum begin guard. DO NO use this as an error.",
+  "Encoder has no registration for this signature.",
+  "Encoder is missing do_register",
+  "Encoder is missing do_encode",
+  "The labcomm buffer is full and it.",
+  "Decoder is missing do_register",
+  "Decoder is missing do_decode_one",
+  "Decoder: Unknown datatype",
+  "Decoder: index mismatch",
+  "Decoder: type not found",
+  "This function is not yet implemented.",
+  "User defined error.",
+  "Could not allocate memory.",
+  "Enum end guard. DO NO use this as an error."
+};
+
+const char *labcomm_error_get_str(enum labcomm_error error_id)
+{
+  const char *error_str = NULL;
+  // Check if this is a known error ID.
+  if (error_id >= LABCOMM_ERROR_ENUM_BEGIN_GUARD && error_id <= LABCOMM_ERROR_ENUM_END_GUARD) {
+    error_str = labcomm_error_strings[error_id];
+  }
+  return error_str;
+}
+
+void labcomm_decoder_register_new_datatype_handler(struct labcomm_decoder *d, labcomm_handle_new_datatype_callback on_new_datatype)
+{
+	d->on_new_datatype = on_new_datatype;
+}
+
+int on_new_datatype(labcomm_decoder_t *d, labcomm_signature_t *sig)
+{
+	  d->on_error(LABCOMM_ERROR_DEC_UNKNOWN_DATATYPE, 4, "%s(): unknown datatype '%s'\n", __FUNCTION__, sig->name);
+	  return 0;
+}
+
+void on_error_fprintf(enum labcomm_error error_id, size_t nbr_va_args, ...)
+{
+#ifndef LABCOMM_NO_STDIO
+  const char *err_msg = labcomm_error_get_str(error_id); // The final string to print.
+  if (err_msg == NULL) {
+    err_msg = "Error with an unknown error ID occured.";
+  }
+  fprintf(stderr, "%s\n", err_msg);
+
+ if (nbr_va_args > 0) {
+   va_list arg_pointer;
+   va_start(arg_pointer, nbr_va_args);
+
+   fprintf(stderr, "%s\n", "Extra info {");
+   char *print_format = va_arg(arg_pointer, char *);
+   vfprintf(stderr, print_format, arg_pointer);
+   fprintf(stderr, "}\n");
+
+   va_end(arg_pointer);
+ } 
+#else
+ ; // If labcomm can't be compiled with stdio the user will have to make an own error callback functionif he/she needs error reporting.
+#endif
+}
+
+
 static labcomm_sample_entry_t *get_sample_by_signature_address(
   labcomm_sample_entry_t *head,
   labcomm_signature_t *signature)
@@ -135,7 +226,7 @@ static void do_encode(
   if (sample && sample->encode) {
     sample->encode(encoder, value);
   } else {
-    printf("Encoder has no registration for %s\n", signature->name);
+    encoder->on_error(LABCOMM_ERROR_ENC_NO_REG_SIGNATURE, 2, "No registration for %s.\n", signature->name);
   }
 }
 
@@ -148,7 +239,7 @@ labcomm_encoder_t *labcomm_encoder_new(
     labcomm_encoder_context_t *context;
 
     context = malloc(sizeof(labcomm_encoder_context_t));
-    context->sample = 0;
+    context->sample = NULL;
     context->index = LABCOMM_USER;
     result->context = context;
     result->writer.context = writer_context;
@@ -158,8 +249,10 @@ labcomm_encoder_t *labcomm_encoder_new(
     result->writer.pos = 0;
     result->writer.write = writer;
     result->writer.write(&result->writer, labcomm_writer_alloc);
+    result->writer.on_error = on_error_fprintf;
     result->do_register = do_encoder_register;
     result->do_encode = do_encode;
+    result->on_error = on_error_fprintf;
   }
   return result;
 }
@@ -169,10 +262,11 @@ void labcomm_internal_encoder_register(
   labcomm_signature_t *signature,
   labcomm_encode_typecast_t encode)
 {
-  if (e && e->do_register) {
+  // Will segfault if e == NULL.
+  if (e->do_register) {
     e->do_register(e, signature, encode);
   } else {
-    printf("Encoder is missing do_register\n");
+    e->on_error(LABCOMM_ERROR_ENC_MISSING_DO_REG, 0);
   }
 }
 
@@ -181,10 +275,11 @@ void labcomm_internal_encode(
   labcomm_signature_t *signature,
   void *value)
 {
-  if (e && e->do_encode) {
+  // Will segfault if e == NULL
+  if (e->do_encode) {
     e->do_encode(e, signature, value);
   } else {
-    printf("Encoder is missing do_encode\n");
+    e->on_error(LABCOMM_ERROR_ENC_MISSING_DO_ENCODE, 0);
   }
 }
 
@@ -196,8 +291,18 @@ void labcomm_internal_encoder_user_action(labcomm_encoder_t *e,
 
 void labcomm_encoder_free(labcomm_encoder_t* e)
 {
-
   e->writer.write(&e->writer, labcomm_writer_free);
+  labcomm_encoder_context_t *econtext = (labcomm_encoder_context_t *) e->context;
+
+  labcomm_sample_entry_t *sentry = econtext->sample;
+  labcomm_sample_entry_t *sentry_next;
+  while (sentry != NULL) {
+    sentry_next = sentry->next;
+    free(sentry);
+    sentry = sentry_next;
+  }
+
+  free(e->context);
   free(e);
 }
 
@@ -251,7 +356,7 @@ static void collect_flat_signature(
 {
   int type = labcomm_decode_int(decoder);
   if (type >= LABCOMM_USER) {
-    printf("Implement %s ...\n", __FUNCTION__);
+    decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 2, "Implement %s\n", __FUNCTION__);
   } else {
     labcomm_encode_int(signature_writer, type);
     switch (type) {
@@ -287,7 +392,7 @@ static void collect_flat_signature(
       case LABCOMM_STRING: {
       } break;
       default: {
-	printf("Implement %s ...\n", __FUNCTION__);
+        decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 2, "Implement %s\n", __FUNCTION__);
       } break;
     }
   }
@@ -343,12 +448,12 @@ static int do_decode_one(labcomm_decoder_t *d)
 	entry = get_sample_by_signature_value(context->sample, &signature);
 	if (! entry) {
 	  // Unknown datatype, bail out
-	  fprintf(stderr,	"%s: unknown datatype '%s' (id=0x%x)\n",
-		  __FUNCTION__, signature.name, index);
+          /*d->on_error(LABCOMM_ERROR_DEC_UNKNOWN_DATATYPE, 4, "%s(): unknown datatype '%s' (id=0x%x)\n", __FUNCTION__, signature.name, index);*/
+		d->on_new_datatype(d, &signature);
 	} else if (entry->index && entry->index != index) {
-	  fprintf(stderr,	"%s: index mismatch '%s' (id=0x%x != 0x%x)\n",
-		  __FUNCTION__, signature.name, entry->index, index);
+          d->on_error(LABCOMM_ERROR_DEC_INDEX_MISMATCH, 5, "%s(): index mismatch '%s' (id=0x%x != 0x%x)\n", __FUNCTION__, signature.name, entry->index, index);
 	} else {
+		// TODO unnessesary, since entry->index == index in above if statement
 	  entry->index = index;
 	}
 	free(signature.name);
@@ -363,8 +468,9 @@ static int do_decode_one(labcomm_decoder_t *d)
 
 	entry = get_sample_by_index(context->sample, result);
 	if (!entry) {
-	  fprintf(stderr,	"%s: type not found (id=0x%x)\n",
-		  __FUNCTION__, result);
+	  // printf("Error: %s: type not found (id=0x%x)\n",
+		  //__FUNCTION__, result);
+          d->on_error(LABCOMM_ERROR_DEC_TYPE_NOT_FOUND, 3, "%s(): type not found (id=0x%x)\n", __FUNCTION__, result);
 	  result = -ENOENT;
 	} else {
 	  entry->decoder(d, entry->handler, entry->context);
@@ -393,8 +499,11 @@ labcomm_decoder_t *labcomm_decoder_new(
     result->reader.pos = 0;
     result->reader.read = reader;
     result->reader.read(&result->reader, labcomm_reader_alloc);
+    result->reader.on_error = on_error_fprintf;
     result->do_register = do_decoder_register;
     result->do_decode_one = do_decode_one;
+    result->on_error = on_error_fprintf;
+	result->on_new_datatype = on_new_datatype;
   }
   return result;
 }
@@ -406,23 +515,25 @@ void labcomm_internal_decoder_register(
   labcomm_handler_typecast_t handler,
   void *handler_context)
 {
-  if (d && d->do_register) {
+  // Will segfault if d == NULL
+  if (d->do_register) {
     d->do_register(d, signature, type_decoder, handler, handler_context);
   } else {
-    printf("Decoder is missing do_register\n");
+    d->on_error(LABCOMM_ERROR_DEC_MISSING_DO_REG, 0);
   }
 }
 
 int labcomm_decoder_decode_one(labcomm_decoder_t *d)
 {
   int result = -1;
-  if (d && d->do_decode_one)
+  // Will segfault if decoder == NULL.
+  if (d->do_decode_one)
   {
     result = d->do_decode_one(d);
   }
   else
   {
-    printf("Decoder is missing do_decode_one\n");
+    d->on_error(LABCOMM_ERROR_DEC_MISSING_DO_DECODE_ONE, 0);
   }
   return result;
 }
@@ -436,5 +547,16 @@ void labcomm_decoder_run(labcomm_decoder_t *d)
 void labcomm_decoder_free(labcomm_decoder_t* d)
 {
   d->reader.read(&d->reader, labcomm_reader_free);
+  labcomm_decoder_context_t *context = (labcomm_decoder_context_t *) d->context;
+  labcomm_sample_entry_t *entry = context->sample;
+  labcomm_sample_entry_t *entry_next;
+
+  while (entry != NULL) {
+    entry_next = entry->next;
+    free(entry);
+    entry = entry_next;
+  }
+
+  free(d->context);
   free(d);
 }
diff --git a/lib/c/labcomm.h b/lib/c/labcomm.h
index 9fed697..5763b8d 100644
--- a/lib/c/labcomm.h
+++ b/lib/c/labcomm.h
@@ -1,10 +1,24 @@
 #ifndef _LABCOMM_H_
 #define _LABCOMM_H_
 
-#include <endian.h>
-#include <stdio.h>
+#ifdef ARM_CORTEXM3_CODESOURCERY
+  #include <machine/endian.h>
+#else
+  #include <endian.h>
+#endif
+
+// Some projects can not use stdio.h.
+#ifndef LABCOMM_NO_STDIO
+  #include <stdio.h>
+#endif
+
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
+
+/* Forward declaration */
+struct labcomm_encoder;
+struct labcomm_decoder;
 
 /*
  * Signature entry
@@ -17,11 +31,62 @@ typedef struct {
   unsigned char *signature; 
 } labcomm_signature_t;
 
+/*
+ * Error handling.
+ */
+
+/* Error IDs */
+enum labcomm_error {
+  LABCOMM_ERROR_ENUM_BEGIN_GUARD,	// _must_ be the first enum element. labcomm_error_get_str() depends on this.
+  LABCOMM_ERROR_ENC_NO_REG_SIGNATURE, 	
+  LABCOMM_ERROR_ENC_MISSING_DO_REG,
+  LABCOMM_ERROR_ENC_MISSING_DO_ENCODE,
+  LABCOMM_ERROR_ENC_BUF_FULL,
+  LABCOMM_ERROR_DEC_MISSING_DO_REG,
+  LABCOMM_ERROR_DEC_MISSING_DO_DECODE_ONE,
+  LABCOMM_ERROR_DEC_UNKNOWN_DATATYPE,
+  LABCOMM_ERROR_DEC_INDEX_MISMATCH,
+  LABCOMM_ERROR_DEC_TYPE_NOT_FOUND,
+  LABCOMM_ERROR_UNIMPLEMENTED_FUNC,
+  LABCOMM_ERROR_MEMORY,
+  LABCOMM_ERROR_USER_DEF,			
+  LABCOMM_ERROR_ENUM_END_GUARD		// _must_ be the last enum element. labcomm_error_get_str() depends on this.
+};
+
+/* Error strings. _must_ be the same order as in enum labcomm_error */
+extern const char *labcomm_error_strings[];
+
+/* The callback prototype for error handling.\
+ * First parameter is the error ID.
+ * The second paramters is the number of va_args that comes after this one. If noneit should be 0.
+ * Optionaly other paramters can be supplied depending on what is needed for this error ID.
+ */
+typedef void (* labcomm_error_handler_callback)(enum labcomm_error error_id, size_t nbr_va_args, ...); 
+
+/* Default error handler, prints message to stderr. 
+ * Extra info about the error can be supplied as char* as VA-args. Especially user defined errors should supply a describing string. if nbr_va_args > 1 the first variable argument must be a printf format string and the possibly following arguments are passed as va_args to vprintf. 
+ */
+void on_error_fprintf(enum labcomm_error error_id, size_t nbr_va_args, ...);
+
+/* Register a callback for the error handler for this encoder. */
+void labcomm_register_error_handler_encoder(struct labcomm_encoder *encoder, labcomm_error_handler_callback callback);
+
+/* Register a callback for the error handler for this decoder. */
+void labcomm_register_error_handler_decoder(struct labcomm_decoder *decoder, labcomm_error_handler_callback callback);
+
+/* Get a string describing the supplied standrad labcomm error. */
+const char *labcomm_error_get_str(enum labcomm_error error_id);
+
+typedef int (* labcomm_handle_new_datatype_callback)(struct labcomm_decoder *decoder,
+		labcomm_signature_t *sig);
+
+void labcomm_decoder_register_new_datatype_handler(struct labcomm_decoder *d,
+		labcomm_handle_new_datatype_callback on_new_datatype);
+
 
 /*
  * Decoder
  */
-struct labcomm_decoder;
 
 typedef enum { 
   labcomm_reader_alloc, 
@@ -38,6 +103,7 @@ typedef struct labcomm_reader {
   int count;
   int pos;
   int (*read)(struct labcomm_reader *, labcomm_reader_action_t);
+  labcomm_error_handler_callback on_error;
 }  labcomm_reader_t;
 
 struct labcomm_decoder *labcomm_decoder_new(
@@ -53,7 +119,6 @@ void labcomm_decoder_free(
 /*
  * Encoder
  */
-struct labcomm_encoder;
 
 typedef enum { 
   labcomm_writer_alloc, 
@@ -71,9 +136,9 @@ typedef struct labcomm_writer {
   int count;
   int pos;
   int (*write)(struct labcomm_writer *, labcomm_writer_action_t);
+  labcomm_error_handler_callback on_error;
 } labcomm_writer_t;
 
-struct labcomm_encoder;
 struct labcomm_encoder *labcomm_encoder_new(
   int (*writer)(labcomm_writer_t *, labcomm_writer_action_t),
   void *writer_context);
diff --git a/lib/c/labcomm_mem_reader.c b/lib/c/labcomm_mem_reader.c
new file mode 100644
index 0000000..088123d
--- /dev/null
+++ b/lib/c/labcomm_mem_reader.c
@@ -0,0 +1,73 @@
+#include "labcomm_mem_reader.h"
+
+#include <errno.h>
+
+/* This implementation assumes labcomm will call end exactly once after each start
+ * It is not allowed to save data in mcontext->enc_data,
+ * this pointer will be set to NULL after decoding.
+ */
+/* NOTE!!!!
+ * start will be run first, once a signature or a data section is decoded
+ * end will be run and then start again. If end of encoded data is reached this
+ * must be handled in start.
+ */
+
+// TODO make labcomm use result!
+int labcomm_mem_reader(labcomm_reader_t *r, labcomm_reader_action_t action)
+{
+  int result = -EINVAL;
+  labcomm_mem_reader_context_t *mcontext = (labcomm_mem_reader_context_t *) r->context;
+
+  switch (action) {
+    case labcomm_reader_alloc: {
+      r->data = NULL;
+      r->data_size = 0;
+      r->pos = 0;
+      r->count = 0;
+      } break;
+    case labcomm_reader_start: {
+      if (r->data == NULL && mcontext->enc_data != NULL) {
+        r->data = (unsigned char *) malloc(mcontext->size);
+        if(r->data != NULL) {
+          memcpy(r->data, mcontext->enc_data, mcontext->size);
+          r->data_size = mcontext->size;
+          r->count = mcontext->size;
+          r->pos = 0;
+          result = r->data_size;
+        } else {
+          r->data_size = 0;
+          result = -ENOMEM;
+        }
+      } else if (r->data == NULL && mcontext->enc_data == NULL) {
+        result = -1;
+      } else {
+        result = r->count - r->pos;
+      }
+    } break;
+    case labcomm_reader_continue: {
+      if (r->pos < r->count) {
+        result = r->count - r->pos;
+      } else {
+        // TODO set some describing error here
+        result = -1;
+      }
+    } break;
+    case labcomm_reader_end: {
+      if (r->pos >= r->count) {
+        free(r->data);
+        r->data = NULL;
+        r->data_size = 0;
+        mcontext->enc_data = NULL;
+        mcontext->size = 0;
+      }
+      result = r->count - r->pos;
+    } break;
+    case labcomm_reader_free: {
+      r->count = 0;
+      r->pos = 0;
+      result = 0;
+    } break;
+  }
+  return result;
+}
+
diff --git a/lib/c/labcomm_mem_reader.h b/lib/c/labcomm_mem_reader.h
new file mode 100644
index 0000000..5cac018
--- /dev/null
+++ b/lib/c/labcomm_mem_reader.h
@@ -0,0 +1,17 @@
+#ifndef LABCOMM_MEM_READER_H
+#define LABCOMM_MEM_READER_H
+
+#include "labcomm.h"
+
+/* enc_data: The data to be decoded
+ * size: the size of the data to be decoded
+ */
+typedef struct labcomm_mem_reader_context_t labcomm_mem_reader_context_t;
+struct labcomm_mem_reader_context_t {
+  size_t size;
+  unsigned char *enc_data;
+};
+
+int labcomm_mem_reader( labcomm_reader_t *r, labcomm_reader_action_t action);
+
+#endif
diff --git a/lib/c/labcomm_mem_writer.c b/lib/c/labcomm_mem_writer.c
new file mode 100644
index 0000000..7275649
--- /dev/null
+++ b/lib/c/labcomm_mem_writer.c
@@ -0,0 +1,143 @@
+#include "labcomm_mem_writer.h"
+
+#include "stddef.h"  // For size_t.
+#include <errno.h>
+
+#include "labcomm.h"
+#include "cppmacros.h"
+
+#define BUFFER_SIZE 150 // Suitable size is at least the size of a fully encoded message. Found by inspecting size of file genreated from the labcomm_fs_reader_writer.c on the same message type.
+
+// Put encdoded data directly in mcontext->mbuf or malloc new temporary memory.
+// 1 == Allocate new memory.
+// 2 == Use mcontext->buf directly. But _beware_; you can not then later change 
+// mcontext->buf to something else since the writer gets a reference to this 
+// buffer!
+#if defined(MEM_WRITER_ENCODED_BUFFER) && (EMPTY(MEM_WRITER_ENCODED_BUFFER) != 1)
+  #define ENCODED_BUFFER MEM_WRITER_ENCODED_BUFFER
+#else
+  #define ENCODED_BUFFER 1
+#endif
+
+static int get_writer_available(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext);
+static void copy_data(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext, unsigned char *mbuf);
+
+/*
+ * Write encoded messages to memory. w->context is assumed to be a pointer to a
+ * labcomm_mem_writer_context_t structure.
+ */
+int labcomm_mem_writer(labcomm_writer_t *w, labcomm_writer_action_t action)
+{
+  int result = 0;
+  // Unwrap pointers for easy access.
+  labcomm_mem_writer_context_t *mcontext = (labcomm_mem_writer_context_t *) w->context;
+  unsigned char *mbuf = mcontext->buf;
+
+  switch (action) {
+  case labcomm_writer_alloc: {
+#if (ENCODED_BUFFER == 1)
+    w->data = malloc(BUFFER_SIZE); // Buffer that LabComm will use for putting the encoded data.
+    if (w->data == NULL) {
+      result = -ENOMEM;
+      w->data_size = 0;
+      w->count = 0;
+      w->pos = 0;
+    } else {
+      w->data_size = BUFFER_SIZE;
+      w->count = BUFFER_SIZE;
+      w->pos = 0;
+    }
+#elif (ENCODED_BUFFER == 2)
+    w->data = mbuf;
+    int bytes_left = (mcontext->length - mcontext->write_pos);
+    w->data_size = bytes_left;
+    w->count = bytes_left;
+    w->pos = mcontext->write_pos;
+#endif
+     } break;
+  case labcomm_writer_free:{
+#if (ENCODED_BUFFER == 1)
+    free(w->data);
+#endif
+    w->data = 0;
+    w->data_size = 0;
+    w->count = 0;
+    w->pos = 0;
+   } break;
+  case labcomm_writer_start:{
+#if (ENCODED_BUFFER == 1)
+    w->pos = 0;
+#elif (ENCODED_BUFFER == 2)
+    w->pos = mcontext->write_pos;
+#endif
+    } break;
+  case labcomm_writer_continue:{ // Encode-buffer(w->data) is full; empty/handle it. (w->pos == w->count) most likely.
+#if (ENCODED_BUFFER == 1)
+    copy_data(w, mcontext, mbuf);
+    result = w->pos; // Assume result here should be number of bytes written.
+    w->pos = 0;
+#elif (ENCODED_BUFFER == 2)
+    mcontext->write_pos = w->pos;
+#endif
+     result = 0;
+       } break;
+  case labcomm_writer_end:{ // Nothing more to encode, handle encode-buffer(w->data).
+#if (ENCODED_BUFFER == 1)
+    copy_data(w, mcontext, mbuf);
+    result = w->pos;
+    w->pos = 0;
+#elif (ENCODED_BUFFER == 2)
+    mcontext->write_pos = w->pos;
+#endif
+    result = 0;
+    } break;
+  case labcomm_writer_available:{
+    result = w->count - w->pos;
+        } break;
+  }
+  return result;
+}
+
+labcomm_mem_writer_context_t *labcomm_mem_writer_context_t_new(size_t init_pos, size_t length, unsigned char *buf)
+{
+  labcomm_mem_writer_context_t *mcontext = (labcomm_mem_writer_context_t *) malloc(sizeof(labcomm_mem_writer_context_t));
+  if (mcontext == NULL) {
+    //fprintf(stderr, "error: Can not allocate labcomm_mem_writer_context_t.\n");
+  } else {
+    mcontext->write_pos = init_pos;
+    mcontext->length = length;
+    mcontext->buf = buf;
+  }
+  return mcontext;
+}
+
+void labcomm_mem_writer_context_t_free(labcomm_mem_writer_context_t **mcontext)
+{
+  free(*mcontext);
+  *mcontext = NULL;
+}
+
+// Get the number of available bytes in the mcontext->buf buffer.
+static int get_writer_available(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext)
+{
+  return (mcontext->length - mcontext->write_pos);
+}
+
+// Copy data from encoded buffer to mbuf.
+static void copy_data(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext, unsigned char *mbuf)
+{
+        int writer_available = get_writer_available(w, mcontext);
+  if (( writer_available - w->pos) < 0) {
+    w->on_error(LABCOMM_ERROR_ENC_BUF_FULL, 3, "labcomm_writer_t->pos=%i, but available in mcontext is %i", w->pos, writer_available); 
+  } else {
+    int i;
+    for (i = 0; i < w->pos; ++i, mcontext->write_pos++) {
+      mbuf[mcontext->write_pos] = w->data[i];
+    }
+  }
+}
+
+void test_copy_data(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext, unsigned char *mbuf)
+{
+  copy_data(w, mcontext, mbuf); 
+}
diff --git a/lib/c/labcomm_mem_writer.h b/lib/c/labcomm_mem_writer.h
new file mode 100644
index 0000000..4585903
--- /dev/null
+++ b/lib/c/labcomm_mem_writer.h
@@ -0,0 +1,25 @@
+#ifndef LABCOMM_MEM_WRITER_H
+#define LABCOMM_MEM_WRITER_H
+
+#include "labcomm.h"
+
+/* Wrapper structure for the memory buffer including a writer position. */
+typedef struct labcomm_mem_writer_context_t labcomm_mem_writer_context_t;
+struct labcomm_mem_writer_context_t {
+  size_t write_pos;  // Position where next write should be.
+  size_t length;  // Length of the buffer.
+  unsigned char *buf;  // Allocated destination buffer.
+};
+
+int labcomm_mem_writer(labcomm_writer_t *w, labcomm_writer_action_t action);
+
+/* Wrapper the internal static function copy_data. This is needed so that the exceptions can be unit tested. */
+void test_copy_data(labcomm_writer_t *w, labcomm_mem_writer_context_t *mcontext, unsigned char *mbuf);
+
+/* Allocate new labcomm_mem_writer_context_t. */
+labcomm_mem_writer_context_t *labcomm_mem_writer_context_t_new(size_t init_pos, size_t length, unsigned char *buf);
+
+/* Deallocate mcontext. */
+void labcomm_mem_writer_context_t_free(labcomm_mem_writer_context_t **mcontext);
+
+#endif
diff --git a/lib/c/labcomm_private.h b/lib/c/labcomm_private.h
index 3bc5140..bd5dcfa 100644
--- a/lib/c/labcomm_private.h
+++ b/lib/c/labcomm_private.h
@@ -1,8 +1,17 @@
 #ifndef _LABCOMM_PRIVATE_H_
 #define _LABCOMM_PRIVATE_H_
 
-#include <endian.h>
-#include <stdio.h>
+#ifdef ARM_CORTEXM3_CODESOURCERY
+  #include <machine/endian.h>
+#else
+  #include <endian.h>
+#endif
+
+// Some projects can not use stdio.h.
+#ifndef LABCOMM_NO_STDIO
+  #include <stdio.h>
+#endif
+
 #include <stdlib.h>
 #include <string.h>
 #include "labcomm.h"
@@ -51,6 +60,8 @@ typedef struct labcomm_decoder {
 		      labcomm_handler_typecast_t,
 		      void *context);
   int (*do_decode_one)(struct labcomm_decoder *decoder);
+  labcomm_error_handler_callback on_error;
+  labcomm_handle_new_datatype_callback on_new_datatype;
 } labcomm_decoder_t;
 
 /*
@@ -176,6 +187,7 @@ typedef struct labcomm_encoder {
   void (*do_encode)(struct labcomm_encoder *encoder, 
 		    labcomm_signature_t *signature, 
 		    void *value);
+  labcomm_error_handler_callback on_error;
 } labcomm_encoder_t;
 
 void labcomm_internal_encoder_register(
@@ -198,7 +210,7 @@ void labcomm_internal_encoder_user_action(struct labcomm_encoder *encoder,
   static inline void labcomm_write_##name(labcomm_writer_t *w, type data) { \
     int i;								\
     for (i = sizeof(type) - 1 ; i >= 0 ; i--) {				\
-      if (w->pos >= w->count) {						\
+      if (w->pos >= w->count) { /*buffer is full*/			\
 	w->write(w, labcomm_writer_continue);				\
       }									\
       w->data[w->pos] = ((unsigned char*)(&data))[i];			\
diff --git a/lib/c/test/test_labcomm.c b/lib/c/test/test_labcomm.c
new file mode 100644
index 0000000..fc4004c
--- /dev/null
+++ b/lib/c/test/test_labcomm.c
@@ -0,0 +1,187 @@
+
+#include "CUnit/Basic.h"
+#include "CUnit/Console.h"
+#include <stdbool.h>
+
+#include <labcomm.h>
+#include <labcomm_mem_writer.h>
+#include <labcomm_mem_reader.h>
+#include "test/testdata/gen/test_sample.h"
+
+#define TEST_BUFFER_SIZE (50)
+
+void test_error_handler(enum labcomm_error error_id, size_t nbr_va_args, ...);
+
+int init_suit_labcomm()
+{
+	return 0;
+}
+
+int clean_suit_labcomm()
+{
+	return 0;
+}
+
+void setup_connected_encoder_decoder(struct labcomm_encoder **enc,
+		labcomm_mem_writer_context_t *enc_ctx,
+		struct labcomm_decoder **dec,
+		labcomm_mem_reader_context_t *dec_ctx)
+{
+	enc_ctx->write_pos = 0;
+	enc_ctx->buf = malloc(TEST_BUFFER_SIZE);
+	enc_ctx->length = TEST_BUFFER_SIZE;
+
+	*enc = labcomm_encoder_new(labcomm_mem_writer, enc_ctx);
+
+	dec_ctx->size = 0;
+	dec_ctx->enc_data = enc_ctx->buf;
+	*dec = labcomm_decoder_new(labcomm_mem_reader, dec_ctx);
+
+	labcomm_register_error_handler_decoder(*dec, test_error_handler);
+	labcomm_register_error_handler_encoder(*enc, test_error_handler);
+}
+
+static bool in_error = false;
+static enum labcomm_error in_error_id = LABCOMM_ERROR_ENUM_BEGIN_GUARD;
+void test_error_handler(enum labcomm_error error_id, size_t nbr_va_args, ...)
+{
+	in_error = true;
+	in_error_id = error_id;
+}
+
+static bool got_sample = false;
+void test_decoder_handle_test_sample_test_var(test_sample_test_var *v, void *ctx)
+{
+	got_sample = true;
+}
+
+void test_decoder_decode_sig()
+{
+	labcomm_mem_writer_context_t enc_ctx;
+	struct labcomm_encoder *encoder;
+	labcomm_mem_reader_context_t dec_ctx;
+	struct labcomm_decoder *decoder;
+	setup_connected_encoder_decoder(&encoder, &enc_ctx, &decoder, &dec_ctx);
+
+	labcomm_encoder_register_test_sample_test_var(encoder);
+	dec_ctx.size = enc_ctx.write_pos;
+
+	labcomm_decoder_register_test_sample_test_var(decoder,
+			test_decoder_handle_test_sample_test_var, NULL);
+	labcomm_decoder_decode_one(decoder);
+
+	CU_ASSERT_FALSE(in_error);
+	enc_ctx.write_pos = 0;
+	test_sample_test_var var = 1;
+	labcomm_encode_test_sample_test_var(encoder, &var);
+	dec_ctx.size = enc_ctx.write_pos;
+	labcomm_decoder_decode_one(decoder);
+
+	CU_ASSERT_FALSE(in_error);
+	CU_ASSERT_FALSE(got_sample);
+
+	labcomm_decoder_free(decoder);
+	labcomm_encoder_free(encoder);
+	free(enc_ctx.buf);
+
+	in_error = false;
+	in_error_id = LABCOMM_ERROR_ENUM_BEGIN_GUARD;
+	got_sample = false;
+}
+
+static bool got_new_datatype = false;
+static labcomm_signature_t new_sig;
+int test_new_datatype(struct labcomm_decoder *decoder,
+		labcomm_signature_t *sig)
+{
+	got_new_datatype = true;
+	memcpy(&new_sig, sig, sizeof(labcomm_signature_t));
+	return 0;
+}
+
+void test_decode_unreg_signature_handle()
+{
+	labcomm_mem_writer_context_t enc_ctx;
+	struct labcomm_encoder *encoder;
+	labcomm_mem_reader_context_t dec_ctx;
+	struct labcomm_decoder *decoder;
+	setup_connected_encoder_decoder(&encoder, &enc_ctx, &decoder, &dec_ctx);
+
+	labcomm_encoder_register_test_sample_test_var(encoder);
+	dec_ctx.size = enc_ctx.write_pos;
+	labcomm_decoder_register_new_datatype_handler(decoder, test_new_datatype);
+	labcomm_decoder_decode_one(decoder);
+
+	CU_ASSERT_TRUE(got_new_datatype);
+	CU_ASSERT_EQUAL(
+			memcmp(new_sig.signature, dec_ctx.enc_data, dec_ctx.size), 0);
+
+	got_new_datatype = false;
+	labcomm_decoder_free(decoder);
+	labcomm_encoder_free(encoder);
+	free(enc_ctx.buf);
+}
+
+void test_decode_unreg_signature_error()
+{
+	labcomm_mem_writer_context_t enc_ctx;
+	struct labcomm_encoder *encoder;
+	labcomm_mem_reader_context_t dec_ctx;
+	struct labcomm_decoder *decoder;
+	setup_connected_encoder_decoder(&encoder, &enc_ctx, &decoder, &dec_ctx);
+
+	labcomm_encoder_register_test_sample_test_var(encoder);
+	dec_ctx.size = enc_ctx.write_pos;
+
+	labcomm_decoder_decode_one(decoder);
+
+	CU_ASSERT_TRUE(in_error);
+	CU_ASSERT_EQUAL(in_error_id, LABCOMM_ERROR_DEC_UNKNOWN_DATATYPE);
+	got_new_datatype = false;
+	labcomm_decoder_free(decoder);
+	labcomm_encoder_free(encoder);
+	free(enc_ctx.buf);
+}
+int main()
+{
+	CU_pSuite suite_decoder = NULL;
+
+	// Initialize CUnit test registry.
+	if (CUE_SUCCESS != CU_initialize_registry()) {
+		return CU_get_error();
+	}
+
+	// Add our test suites.
+	suite_decoder = CU_add_suite("transport_enc_dec",
+			init_suit_labcomm, clean_suit_labcomm);
+	if (suite_decoder == NULL) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+
+	if (
+			(CU_add_test(suite_decoder, "test_decoder_decode_sig",
+					test_decoder_decode_sig) == NULL)
+			||
+			(CU_add_test(suite_decoder, "test_decode_unreg_signature_handle",
+					test_decode_unreg_signature_handle) == NULL)
+			||
+			(CU_add_test(suite_decoder, "test_decode_unreg_signature_error",
+					test_decode_unreg_signature_error) == NULL)
+		) {
+		CU_cleanup_registry();
+		return CU_get_error();
+	}
+
+	// Set verbosity.
+	CU_basic_set_mode(CU_BRM_VERBOSE);
+	/*CU_console_run_tests();*/
+
+	// Run all test suites.
+	CU_basic_run_tests();
+
+	// Clean up.
+	CU_cleanup_registry();
+
+	return CU_get_error();
+}
diff --git a/lib/c/test/test_labcomm_errors b/lib/c/test/test_labcomm_errors
new file mode 100755
index 0000000000000000000000000000000000000000..061b60594868d10026d20b7d650a188827d456ab
GIT binary patch
literal 46272
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

literal 0
HcmV?d00001

diff --git a/lib/c/test/test_labcomm_errors.c b/lib/c/test/test_labcomm_errors.c
new file mode 100644
index 0000000..7742175
--- /dev/null
+++ b/lib/c/test/test_labcomm_errors.c
@@ -0,0 +1,168 @@
+#include "test_labcomm_errors.h"
+
+#include <stdlib.h>
+
+#include <labcomm.h>
+#include <labcomm_private.h>
+#include <labcomm_mem_writer.h>
+#include <labcomm_mem_reader.h>
+
+static enum labcomm_error callback_error_id;
+
+int assert_callback(enum labcomm_error expected, const char *name, const char *err_msg)
+{
+  int success;
+  printf("----> %s()\n", name);
+  if (callback_error_id == expected) {
+    printf("Succeeded.\n");
+    success = 1;
+  } else {
+    printf("Failed! %s\n", err_msg);
+    success = 0;
+  }
+  return success;
+}
+
+/* Our callback that just logs which error_id that the library reported. */
+void test_callback(enum labcomm_error error_id, size_t nbr_va_args, ...)
+{
+   va_list arg_pointer;
+   va_start(arg_pointer, nbr_va_args);
+   va_end(arg_pointer);
+   callback_error_id = error_id;
+}
+ 
+void reset_callback_erro_id()
+{
+  callback_error_id = -128;
+}
+
+int encoded_size_mock(void *voidp)
+{
+  return 0;
+}
+
+int test_enc_not_reg_encoder_sign()
+{
+  reset_callback_erro_id();
+  unsigned char *buf = (unsigned char *) "a";
+  labcomm_mem_writer_context_t *mcontext = labcomm_mem_writer_context_t_new(0, 1, buf);
+  labcomm_encoder_t *encoder = labcomm_encoder_new(labcomm_mem_writer, mcontext);
+  labcomm_register_error_handler_encoder(encoder, test_callback);
+  
+  labcomm_signature_t signature = {.type = 0, .name = "test_signature", .encoded_size = encoded_size_mock, .size = 0, .signature = (unsigned char *) "0"};
+  encoder->do_encode(encoder, &signature, NULL);
+
+  return assert_callback(LABCOMM_ERROR_ENC_NO_REG_SIGNATURE, __FUNCTION__, "");
+}
+
+int test_enc_missing_do_reg()
+{
+  reset_callback_erro_id();
+  unsigned char *buf = (unsigned char *) "a";
+  labcomm_mem_writer_context_t *mcontext = labcomm_mem_writer_context_t_new(0, 1, buf);
+  labcomm_encoder_t *encoder = labcomm_encoder_new(labcomm_mem_writer, mcontext);
+  labcomm_register_error_handler_encoder(encoder, test_callback);
+
+  encoder->do_register = NULL;
+  labcomm_internal_encoder_register(encoder, NULL, NULL);
+
+  return assert_callback(LABCOMM_ERROR_ENC_MISSING_DO_REG, __FUNCTION__, "");
+}
+
+int test_enc_missing_do_encode()
+{
+  reset_callback_erro_id();
+  unsigned char *buf = (unsigned char *) "a";
+  labcomm_mem_writer_context_t *mcontext = labcomm_mem_writer_context_t_new(0, 1, buf);
+  labcomm_encoder_t *encoder = labcomm_encoder_new(labcomm_mem_writer, mcontext);
+  labcomm_register_error_handler_encoder(encoder, test_callback);
+
+  encoder->do_encode = NULL;
+  labcomm_internal_encode(encoder, NULL, NULL);
+
+  return assert_callback(LABCOMM_ERROR_ENC_MISSING_DO_ENCODE, __FUNCTION__, "");
+}
+
+int test_enc_buf_full()
+{
+  reset_callback_erro_id();
+  unsigned char *buf = (unsigned char *) "a";
+  labcomm_mem_writer_context_t *mcontext = labcomm_mem_writer_context_t_new(0, 1, buf);
+  labcomm_encoder_t *encoder = labcomm_encoder_new(labcomm_mem_writer, mcontext);
+  labcomm_register_error_handler_encoder(encoder, test_callback);
+
+  unsigned char *mbuf = mcontext->buf;
+  labcomm_writer_t writer = encoder->writer;
+  writer.data = malloc(1);
+  writer.pos = 1;
+  mcontext->write_pos = 1;
+  test_copy_data(&writer, mcontext, mbuf);
+
+  return assert_callback(LABCOMM_ERROR_ENC_BUF_FULL, __FUNCTION__, "");
+}
+
+void labcomm_decoder_typecast_t_mock(struct labcomm_decoder *decoder, labcomm_handler_typecast_t handler, void *voidp)
+{
+        ;
+}
+
+void labcomm_handler_typecast_t_mock(void *arg1, void *arg2)
+{
+        ;
+}
+
+int test_dec_missing_do_reg()
+{
+  reset_callback_erro_id();
+  unsigned char *buf = (unsigned char *) "a";
+  labcomm_mem_reader_context_t *mcontext = (labcomm_mem_reader_context_t *) malloc(sizeof(labcomm_mem_reader_context_t));
+  labcomm_decoder_t *decoder = labcomm_decoder_new(labcomm_mem_reader, mcontext);
+  labcomm_register_error_handler_decoder(decoder, test_callback);
+  
+  decoder->do_register = NULL;
+  labcomm_internal_decoder_register(decoder, NULL, labcomm_decoder_typecast_t_mock, labcomm_handler_typecast_t_mock, buf);
+
+  return assert_callback(LABCOMM_ERROR_DEC_MISSING_DO_REG, __FUNCTION__, "");
+}
+
+int test_dec_missing_do_decode_one()
+{
+  reset_callback_erro_id();
+  labcomm_mem_reader_context_t *mcontext = (labcomm_mem_reader_context_t *) malloc(sizeof(labcomm_mem_reader_context_t));
+  labcomm_decoder_t *decoder = labcomm_decoder_new(labcomm_mem_reader, mcontext);
+  labcomm_register_error_handler_decoder(decoder, test_callback);
+  
+  decoder->do_decode_one = NULL;
+  labcomm_decoder_decode_one(decoder);
+
+  return assert_callback(LABCOMM_ERROR_DEC_MISSING_DO_DECODE_ONE, __FUNCTION__, "");
+}
+
+int main()
+{
+  printf("####> Begin tests.\n");
+  size_t nbr_succeed = 0;
+  size_t nbr_tests = 6; // Increment this when new tests are written.
+  nbr_succeed += test_enc_not_reg_encoder_sign();
+  nbr_succeed += test_enc_missing_do_reg();
+  nbr_succeed += test_enc_missing_do_encode();
+  nbr_succeed += test_enc_buf_full();
+  nbr_succeed += test_dec_missing_do_reg();
+  nbr_succeed += test_dec_missing_do_decode_one();
+
+  // Too tedius to test really...
+  //nbr_succeed += test_dec_unknown_datatype();
+  //nbr_succeed += test_dec_index_mismatch();
+  //nbr_succeed += test_dec_type_not_found();
+
+  //nbr_succeed += test_unimplemented_func(); // This test will be obsolete in the future ;-)
+  //nbr_succeed += test_user_def();           // There are no user defined errors in the library of course.
+
+  printf("####> End tests.\nSummary: %i/%i tests succeed.\n", nbr_succeed, nbr_tests);
+  if (nbr_succeed == nbr_tests) {
+	  return EXIT_SUCCESS;
+  } else {
+  	  return EXIT_FAILURE;
+  }
+}
diff --git a/lib/c/test/test_labcomm_errors.h b/lib/c/test/test_labcomm_errors.h
new file mode 100644
index 0000000..8cc3918
--- /dev/null
+++ b/lib/c/test/test_labcomm_errors.h
@@ -0,0 +1,6 @@
+#ifndef TEST_LABCOMM_ERRORS_H
+#define TEST_LABCOMM_ERRORS_H
+
+void test_not_reg_encoder_sign();
+
+#endif
diff --git a/lib/c/test/testdata/test_sample.lc b/lib/c/test/testdata/test_sample.lc
new file mode 100644
index 0000000..bf686a7
--- /dev/null
+++ b/lib/c/test/testdata/test_sample.lc
@@ -0,0 +1 @@
+sample int test_var;
-- 
GitLab