From e23fb6d20ddcd15e3a511d75a377b68fdd7fef0d Mon Sep 17 00:00:00 2001
From: Jan Breuer <jan.breuer@jaybee.cz>
Date: 周日, 24 4月 2016 22:16:50 +0800
Subject: [PATCH] Merge branch 'feature/SCPI_99_21_8_Device_dependent_error_information_73' and solve #73

---
 examples/common/scpi-def.h     |    2 
 libscpi/src/minimal.c          |   40 +-
 libscpi/src/parser.c           |  110 +++++++
 libscpi/inc/scpi/config.h      |   29 ++
 libscpi/src/utils_private.h    |    7 
 libscpi/src/error.c            |   68 +++-
 libscpi/src/fifo.c             |   16 
 libscpi/inc/scpi/constants.h   |    5 
 examples/common/scpi-def.c     |    2 
 libscpi/inc/scpi/error.h       |    5 
 libscpi/inc/scpi/types.h       |   22 +
 libscpi/src/fifo_private.h     |    8 
 libscpi/test/test_scpi_utils.c |   58 ++++
 .travis.yml                    |    2 
 libscpi/inc/scpi/parser.h      |    6 
 libscpi/test/test_parser.c     |  177 ++++++++---
 libscpi/src/utils.c            |  158 ++++++++++
 libscpi/test/test_fifo.c       |   77 +++--
 18 files changed, 637 insertions(+), 155 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index bd59bd8..122d9c1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -24,6 +24,8 @@
 script:
   - make
   - CC=clang CFLAGS="-g -O0 -fsanitize=address" LDFLAGS="-g -fsanitize=address" make clean test
+  - CC=clang CFLAGS="-g -O0 -fsanitize=address -DUSE_DEVICE_DEPENDENT_ERROR_INFORMATION=0" LDFLAGS="-g -fsanitize=address" make clean test
+  - CC=clang CFLAGS="-g -O0 -fsanitize=address -DUSE_MEMORY_ALLOCATION_FREE=0" LDFLAGS="-g -fsanitize=address" make clean test
   - CFLAGS="-m32" LDFLAGS="-m32 -L$PWD/CUnit/CUnit/Sources/.libs/" make clean test
   - LDFLAGS="-lgcov" CFLAGS="-fprofile-arcs -ftest-coverage" make clean all test
 
diff --git a/examples/common/scpi-def.c b/examples/common/scpi-def.c
index 809fb1e..d5f71ae 100644
--- a/examples/common/scpi-def.c
+++ b/examples/common/scpi-def.c
@@ -412,6 +412,6 @@
 };
 
 char scpi_input_buffer[SCPI_INPUT_BUFFER_LENGTH];
-int16_t scpi_error_queue_data[SCPI_ERROR_QUEUE_SIZE];
+scpi_error_t scpi_error_queue_data[SCPI_ERROR_QUEUE_SIZE];
 
 scpi_t scpi_context;
diff --git a/examples/common/scpi-def.h b/examples/common/scpi-def.h
index 908f80b..f451300 100644
--- a/examples/common/scpi-def.h
+++ b/examples/common/scpi-def.h
@@ -13,7 +13,7 @@
 extern const scpi_command_t scpi_commands[];
 extern scpi_interface_t scpi_interface;
 extern char scpi_input_buffer[];
-extern int16_t scpi_error_queue_data[];
+extern scpi_error_t scpi_error_queue_data[];
 extern scpi_t scpi_context;
 
 size_t SCPI_Write(scpi_t * context, const char * data, size_t len);
diff --git a/libscpi/inc/scpi/config.h b/libscpi/inc/scpi/config.h
index 45a9c3c..0abb9c2 100644
--- a/libscpi/inc/scpi/config.h
+++ b/libscpi/inc/scpi/config.h
@@ -89,6 +89,16 @@
 #define USE_USER_ERROR_LIST 0
 #endif
 
+#ifndef USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+#define USE_DEVICE_DEPENDENT_ERROR_INFORMATION SYSTEM_TYPE
+#endif
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+#ifndef USE_MEMORY_ALLOCATION_FREE
+#define USE_MEMORY_ALLOCATION_FREE 1
+#endif
+#endif
+
 #ifndef USE_COMMAND_TAGS
 #define USE_COMMAND_TAGS 1
 #endif
@@ -251,6 +261,25 @@
 #define SCPIDEFINE_doubleToStr(v, s, l) snprintf((s), (l), "%.15lg", (v))
 #endif
 
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+
+#if USE_MEMORY_ALLOCATION_FREE
+#include <stdlib.h>
+#include <string.h>
+#define SCPIDEFINE_DESCRIPTION_MAX_PARTS		2
+#define SCPIDEFINE_strndup(h, s, l)                     strndup((s), (l))
+#define SCPIDEFINE_free(h, s, r)                        free((s))
+#else
+#define SCPIDEFINE_DESCRIPTION_MAX_PARTS                3
+#define SCPIDEFINE_strndup(h, s, l)                     scpiheap_strndup((h), (s), (l))
+#define SCPIDEFINE_free(h, s, r)                        scpiheap_free((h), (s), (r))
+#define SCPIDEFINE_get_parts(h, s, l1, s2, l2)          scpiheap_get_parts((h), (s), (l1), (s2), (l2))
+#endif
+#else
+#define SCPIDEFINE_DESCRIPTION_MAX_PARTS                1
+#define SCPIDEFINE_strndup(h, s, l)                     NULL
+#define SCPIDEFINE_free(h, s, r)
+#endif
 
 #ifdef	__cplusplus
 }
diff --git a/libscpi/inc/scpi/constants.h b/libscpi/inc/scpi/constants.h
index 61cd9a6..ecbfb55 100644
--- a/libscpi/inc/scpi/constants.h
+++ b/libscpi/inc/scpi/constants.h
@@ -48,6 +48,11 @@
      */
 #define SCPI_STD_VERSION_REVISION "1999.0"
 
+/* 21.8 :ERRor Subsystem
+ * The maximum string length of <Error/event_description> plus <Device-dependent_info> is 255 characters.
+ */
+#define SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH 255
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/libscpi/inc/scpi/error.h b/libscpi/inc/scpi/error.h
index 916ca25..6c7d744 100644
--- a/libscpi/inc/scpi/error.h
+++ b/libscpi/inc/scpi/error.h
@@ -44,9 +44,10 @@
 extern "C" {
 #endif
 
-    void SCPI_ErrorInit(scpi_t * context, int16_t * data, int16_t size);
+    void SCPI_ErrorInit(scpi_t * context, scpi_error_t * data, int16_t size);
     void SCPI_ErrorClear(scpi_t * context);
-    int16_t SCPI_ErrorPop(scpi_t * context);
+    scpi_bool_t SCPI_ErrorPop(scpi_t * context, scpi_error_t * error);
+    void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info, size_t info_len);
     void SCPI_ErrorPush(scpi_t * context, int16_t err);
     int32_t SCPI_ErrorCount(scpi_t * context);
     const char * SCPI_ErrorTranslate(int16_t err);
diff --git a/libscpi/inc/scpi/parser.h b/libscpi/inc/scpi/parser.h
index 84a433d..2f00c82 100644
--- a/libscpi/inc/scpi/parser.h
+++ b/libscpi/inc/scpi/parser.h
@@ -49,7 +49,10 @@
             const scpi_unit_def_t * units,
             const char * idn1, const char * idn2, const char * idn3, const char * idn4,
             char * input_buffer, size_t input_buffer_length, 
-            int16_t * error_queue_data, int16_t error_queue_size);
+            scpi_error_t * error_queue_data, int16_t error_queue_size);
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+    void SCPI_InitHeap(scpi_t * context, char * error_info_heap, size_t error_info_heap_length);
+#endif
 
     scpi_bool_t SCPI_Input(scpi_t * context, const char * data, int len);
     scpi_bool_t SCPI_Parse(scpi_t * context, char * data, int len);
@@ -71,6 +74,7 @@
     size_t SCPI_ResultFloat(scpi_t * context, float val);
     size_t SCPI_ResultDouble(scpi_t * context, double val);
     size_t SCPI_ResultText(scpi_t * context, const char * data);
+	size_t SCPI_ResultError(scpi_t * context, scpi_error_t * error);
     size_t SCPI_ResultArbitraryBlock(scpi_t * context, const void * data, size_t len);
     size_t SCPI_ResultArbitraryBlockHeader(scpi_t * context, size_t len);
     size_t SCPI_ResultArbitraryBlockData(scpi_t * context, const void * data, size_t len);
diff --git a/libscpi/inc/scpi/types.h b/libscpi/inc/scpi/types.h
index 01611be..c8ddf2e 100644
--- a/libscpi/inc/scpi/types.h
+++ b/libscpi/inc/scpi/types.h
@@ -201,12 +201,29 @@
 
     typedef scpi_result_t(*scpi_command_callback_t)(scpi_t *);
 
+    struct _scpi_error_info_heap_t {
+        size_t wr;
+        //size_t rd;
+        size_t count;
+        size_t size;
+        char * data;
+    };
+    typedef struct _scpi_error_info_heap_t scpi_error_info_heap_t;
+
+    struct _scpi_error_t {
+        int16_t error_code;
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+        char * device_dependent_info;
+#endif
+    };
+    typedef struct _scpi_error_t scpi_error_t;
+
     struct _scpi_fifo_t {
         int16_t wr;
         int16_t rd;
         int16_t count;
         int16_t size;
-        int16_t * data;
+        scpi_error_t * data;
     };
     typedef struct _scpi_fifo_t scpi_fifo_t;
 
@@ -350,6 +367,9 @@
         int_fast16_t input_count;
         scpi_bool_t cmd_error;
         scpi_fifo_t error_queue;
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+        scpi_error_info_heap_t error_info_heap;
+#endif
         scpi_reg_val_t registers[SCPI_REG_COUNT];
         const scpi_unit_def_t * units;
         void * user_context;
diff --git a/libscpi/src/error.c b/libscpi/src/error.c
index feec31f..b2bedfc 100644
--- a/libscpi/src/error.c
+++ b/libscpi/src/error.c
@@ -40,12 +40,19 @@
 #include "scpi/ieee488.h"
 #include "scpi/error.h"
 #include "fifo_private.h"
+#include "scpi/constants.h"
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+#define SCPI_ERROR_SETVAL(e, c, i) do { (e)->error_code = (c); (e)->device_dependent_info = (i); } while(0)
+#else
+#define SCPI_ERROR_SETVAL(e, c, i) do { (e)->error_code = (c); } while(0)
+#endif
 
 /**
  * Initialize error queue
  * @param context - scpi context
  */
-void SCPI_ErrorInit(scpi_t * context, int16_t * data, int16_t size) {
+void SCPI_ErrorInit(scpi_t * context, scpi_error_t * data, int16_t size) {
     fifo_init(&context->error_queue, data, size);
 }
 
@@ -81,6 +88,12 @@
  * @param context - scpi context
  */
 void SCPI_ErrorClear(scpi_t * context) {
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+    scpi_error_t error;
+    while (fifo_remove(&context->error_queue, &error)) {
+        SCPIDEFINE_free(&context->error_info_heap, error.device_dependent_info, false);
+    }
+#endif
     fifo_clear(&context->error_queue);
 
     SCPI_ErrorEmitEmpty(context);
@@ -89,16 +102,17 @@
 /**
  * Pop error from queue
  * @param context - scpi context
- * @return error number
+ * @param error
+ * @return
  */
-int16_t SCPI_ErrorPop(scpi_t * context) {
-    int16_t result = 0;
-
-    fifo_remove(&context->error_queue, &result);
+scpi_bool_t SCPI_ErrorPop(scpi_t * context, scpi_error_t * error) {
+    if (!error || !context) return FALSE;
+    SCPI_ERROR_SETVAL(error, 0, NULL);
+    fifo_remove(&context->error_queue, error);
 
     SCPI_ErrorEmitEmpty(context);
 
-    return result;
+    return TRUE;
 }
 
 /**
@@ -114,10 +128,16 @@
     return result;
 }
 
-static scpi_bool_t SCPI_ErrorAddInternal(scpi_t * context, int16_t err) {
-    if (!fifo_add(&context->error_queue, err)) {
-        fifo_remove_last(&context->error_queue, NULL);
-        fifo_add(&context->error_queue, SCPI_ERROR_QUEUE_OVERFLOW);
+static scpi_bool_t SCPI_ErrorAddInternal(scpi_t * context, int16_t err, char * info, size_t info_len) {
+    scpi_error_t error_value;
+    char * info_ptr = info ? SCPIDEFINE_strndup(&context->error_info_heap, info, info_len) : NULL;
+    SCPI_ERROR_SETVAL(&error_value, err, info_ptr);
+    if (!fifo_add(&context->error_queue, &error_value)) {
+        SCPIDEFINE_free(&context->error_info_heap, error_value.device_dependent_info, true);
+        fifo_remove_last(&context->error_queue, &error_value);
+        SCPIDEFINE_free(&context->error_info_heap, error_value.device_dependent_info, true);
+        SCPI_ERROR_SETVAL(&error_value, SCPI_ERROR_QUEUE_OVERFLOW, NULL);
+        fifo_add(&context->error_queue, &error_value);
         return FALSE;
     }
     return TRUE;
@@ -129,7 +149,7 @@
     scpi_reg_val_t esrBit;
 };
 
-#define ERROR_DEFS_N	9
+#define ERROR_DEFS_N 9
 
 static const struct error_reg errs[ERROR_DEFS_N] = {
     {-100, -199, ESR_CER}, /* Command error (e.g. syntax error) ch 21.8.9    */
@@ -145,14 +165,18 @@
 
 /**
  * Push error to queue
- * @param context - scpi context
+ * @param context
  * @param err - error number
+ * @param info - additional text information or NULL for no text
+ * @param info_len - length of text or 0 for automatic length
  */
-void SCPI_ErrorPush(scpi_t * context, int16_t err) {
-
+void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info, size_t info_len) {
     int i;
-
-    scpi_bool_t queue_overflow = !SCPI_ErrorAddInternal(context, err);
+    /* automatic calculation of length */
+    if (info && info_len == 0) {
+        info_len = SCPIDEFINE_strnlen(info, SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH);
+    }
+    scpi_bool_t queue_overflow = !SCPI_ErrorAddInternal(context, err, info, info_len);
 
     for (i = 0; i < ERROR_DEFS_N; i++) {
         if ((err <= errs[i].from) && (err >= errs[i].to)) {
@@ -171,6 +195,16 @@
 }
 
 /**
+ * Push error to queue
+ * @param context - scpi context
+ * @param err - error number
+ */
+void SCPI_ErrorPush(scpi_t * context, int16_t err) {
+    SCPI_ErrorPushEx(context, err, NULL, 0);
+    return;
+}
+
+/**
  * Translate error number to string
  * @param err - error number
  * @return Error string representation
diff --git a/libscpi/src/fifo.c b/libscpi/src/fifo.c
index e81f55e..a97ab7a 100644
--- a/libscpi/src/fifo.c
+++ b/libscpi/src/fifo.c
@@ -5,7 +5,7 @@
  * Initialize fifo
  * @param fifo
  */
-void fifo_init(scpi_fifo_t * fifo, int16_t * data, int16_t size) {
+void fifo_init(scpi_fifo_t * fifo, scpi_error_t * data, int16_t size) {
     fifo->wr = 0;
     fifo->rd = 0;
     fifo->count = 0;
@@ -44,16 +44,20 @@
 /**
  * Add element to fifo. If fifo is full, return FALSE.
  * @param fifo
- * @param value
+ * @param err
+ * @param info
  * @return
  */
-scpi_bool_t fifo_add(scpi_fifo_t * fifo, int16_t value) {
+scpi_bool_t fifo_add(scpi_fifo_t * fifo, const scpi_error_t * value) {
     /* FIFO full? */
     if (fifo_is_full(fifo)) {
         return FALSE;
     }
+    if (!value) {
+        return FALSE;
+    }
 
-    fifo->data[fifo->wr] = value;
+    fifo->data[fifo->wr] = *value;
     fifo->wr = (fifo->wr + 1) % (fifo->size);
     fifo->count += 1;
     return TRUE;
@@ -65,7 +69,7 @@
  * @param value
  * @return FALSE - fifo is empty
  */
-scpi_bool_t fifo_remove(scpi_fifo_t * fifo, int16_t * value) {
+scpi_bool_t fifo_remove(scpi_fifo_t * fifo, scpi_error_t * value) {
     /* FIFO empty? */
     if (fifo_is_empty(fifo)) {
         return FALSE;
@@ -87,7 +91,7 @@
  * @param value
  * @return FALSE - fifo is empty
  */
-scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, int16_t * value) {
+scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, scpi_error_t * value) {
     /* FIFO empty? */
     if (fifo_is_empty(fifo)) {
         return FALSE;
diff --git a/libscpi/src/fifo_private.h b/libscpi/src/fifo_private.h
index f1a1d12..0bc70fd 100644
--- a/libscpi/src/fifo_private.h
+++ b/libscpi/src/fifo_private.h
@@ -44,13 +44,13 @@
 extern "C" {
 #endif
 
-    void fifo_init(scpi_fifo_t * fifo, int16_t * data, int16_t size) LOCAL;
+    void fifo_init(scpi_fifo_t * fifo, scpi_error_t * data, int16_t size) LOCAL;
     void fifo_clear(scpi_fifo_t * fifo) LOCAL;
     scpi_bool_t fifo_is_empty(scpi_fifo_t * fifo) LOCAL;
     scpi_bool_t fifo_is_full(scpi_fifo_t * fifo) LOCAL;
-    scpi_bool_t fifo_add(scpi_fifo_t * fifo, int16_t value) LOCAL;
-    scpi_bool_t fifo_remove(scpi_fifo_t * fifo, int16_t * value) LOCAL;
-    scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, int16_t * value) LOCAL;
+    scpi_bool_t fifo_add(scpi_fifo_t * fifo, const scpi_error_t * value) LOCAL;
+    scpi_bool_t fifo_remove(scpi_fifo_t * fifo, scpi_error_t * value) LOCAL;
+    scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, scpi_error_t * value) LOCAL;
     scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) LOCAL;
 
 #ifdef	__cplusplus
diff --git a/libscpi/src/minimal.c b/libscpi/src/minimal.c
index 7641311..83ecec7 100644
--- a/libscpi/src/minimal.c
+++ b/libscpi/src/minimal.c
@@ -2,7 +2,7 @@
  * Copyright (c) 2012-2013 Jan Breuer,
  *
  * All Rights Reserved
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
@@ -11,7 +11,7 @@
  * 2. 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.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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
@@ -28,10 +28,10 @@
 /**
  * @file   scpi_minimal.c
  * @date   Thu Nov 15 10:58:45 UTC 2012
- * 
+ *
  * @brief  SCPI minimal implementation
- * 
- * 
+ *
+ *
  */
 
 
@@ -40,11 +40,12 @@
 #include "scpi/constants.h"
 #include "scpi/error.h"
 #include "scpi/ieee488.h"
+#include "utils_private.h"
 
 /**
  * Command stub function
  * @param context
- * @return 
+ * @return
  */
 scpi_result_t SCPI_Stub(scpi_t * context) {
     (void) context;
@@ -54,7 +55,7 @@
 /**
  * Query command stub function
  * @param context
- * @return 
+ * @return
  */
 scpi_result_t SCPI_StubQ(scpi_t * context) {
     SCPI_ResultInt32(context, 0);
@@ -64,7 +65,7 @@
 /**
  * SYSTem:VERSion?
  * @param context
- * @return 
+ * @return
  */
 scpi_result_t SCPI_SystemVersionQ(scpi_t * context) {
     SCPI_ResultMnemonic(context, SCPI_STD_VERSION_REVISION);
@@ -74,21 +75,22 @@
 /**
  * SYSTem:ERRor[:NEXT]?
  * @param context
- * @return 
+ * @return
  */
 scpi_result_t SCPI_SystemErrorNextQ(scpi_t * context) {
-    int16_t err = SCPI_ErrorPop(context);
-
-    SCPI_ResultInt32(context, err);
-    SCPI_ResultText(context, SCPI_ErrorTranslate(err));
-
+    scpi_error_t error;
+    SCPI_ErrorPop(context, &error);
+    SCPI_ResultError(context, &error);
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+    SCPIDEFINE_free(&context->error_info_heap, error.device_dependent_info, false);
+#endif
     return SCPI_RES_OK;
 }
 
 /**
  * SYSTem:ERRor:COUNt?
  * @param context
- * @return 
+ * @return
  */
 scpi_result_t SCPI_SystemErrorCountQ(scpi_t * context) {
     SCPI_ResultInt32(context, SCPI_ErrorCount(context));
@@ -99,7 +101,7 @@
 /**
  * STATus:QUEStionable[:EVENt]?
  * @param context
- * @return 
+ * @return
  */
 scpi_result_t SCPI_StatusQuestionableEventQ(scpi_t * context) {
     /* return value */
@@ -114,7 +116,7 @@
 /**
  * STATus:QUEStionable:ENABle?
  * @param context
- * @return 
+ * @return
  */
 scpi_result_t SCPI_StatusQuestionableEnableQ(scpi_t * context) {
     /* return value */
@@ -126,7 +128,7 @@
 /**
  * STATus:QUEStionable:ENABle
  * @param context
- * @return 
+ * @return
  */
 scpi_result_t SCPI_StatusQuestionableEnable(scpi_t * context) {
     int32_t new_QUESE;
@@ -139,7 +141,7 @@
 /**
  * STATus:PRESet
  * @param context
- * @return 
+ * @return
  */
 scpi_result_t SCPI_StatusPreset(scpi_t * context) {
     /* clear STATUS:... */
diff --git a/libscpi/src/parser.c b/libscpi/src/parser.c
index 7849e2a..db6f5df 100644
--- a/libscpi/src/parser.c
+++ b/libscpi/src/parser.c
@@ -219,7 +219,11 @@
                 result &= processCommand(context);
                 cmd_prev = state->programHeader;
             } else {
-                SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER);
+                /* place undefined header with error */
+                /* calculate length of errornouse header and trim \r\n */
+                size_t r2 = r;
+                while(r2 > 0 && (data[r2 - 1] == '\r' || data[r2 - 1] == '\n')) r2--;
+                SCPI_ErrorPushEx(context, SCPI_ERROR_UNDEFINED_HEADER, data, r2);
                 result = FALSE;
             }
         }
@@ -242,18 +246,26 @@
 /**
  * Initialize SCPI context structure
  * @param context
- * @param command_list
- * @param buffer
+ * @param commands
  * @param interface
+ * @param units
+ * @param idn1
+ * @param idn2
+ * @param idn3
+ * @param idn4
+ * @param input_buffer
+ * @param input_buffer_length
+ * @param error_queue_data
+ * @param error_queue_size
  */
-void SCPI_Init(scpi_t * context, 
+void SCPI_Init(scpi_t * context,
         const scpi_command_t * commands,
         scpi_interface_t * interface,
         const scpi_unit_def_t * units,
         const char * idn1, const char * idn2, const char * idn3, const char * idn4,
-        char * input_buffer, size_t input_buffer_length, 
-        int16_t * error_queue_data, int16_t error_queue_size) {
-    memset(context, 0, sizeof(*context));
+        char * input_buffer, size_t input_buffer_length,
+        scpi_error_t * error_queue_data, int16_t error_queue_size) {
+    memset(context, 0, sizeof (*context));
     context->cmdlist = commands;
     context->interface = interface;
     context->units = units;
@@ -266,6 +278,20 @@
     context->buffer.position = 0;
     SCPI_ErrorInit(context, error_queue_data, error_queue_size);
 }
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+/**
+ * Initialize context's
+ * @param context
+ * @param data
+ * @param len
+ * @return
+ */
+void SCPI_InitHeap(scpi_t * context,
+        char * error_info_heap, size_t error_info_heap_length) {
+    scpiheap_init(&context->error_info_heap, error_info_heap, error_info_heap_length);
+}
+#endif
 
 /**
  * Interface to the application. Adds data to system buffer and try to search
@@ -501,6 +527,76 @@
 }
 
 /**
+ * SCPI-99:21.8 Device-dependent error information.
+ * Write error information with the following syntax:
+ * <Error/event_number>,"<Error/event_description>[;<Device-dependent_info>]"
+ * The maximum string length of <Error/event_description> plus <Device-dependent_info>
+ * is SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH (255) characters.
+ *
+ * @param context
+ * @param error
+ * @return
+ */
+size_t SCPI_ResultError(scpi_t * context, scpi_error_t * error) {
+    size_t result = 0;
+    size_t outputlimit = SCPI_STD_ERROR_DESC_MAX_STRING_LENGTH;
+    size_t step = 0;
+    const char * quote;
+
+    const char * data[SCPIDEFINE_DESCRIPTION_MAX_PARTS];
+    size_t len[SCPIDEFINE_DESCRIPTION_MAX_PARTS];
+    size_t i;
+
+    data[0] = SCPI_ErrorTranslate(error->error_code);
+    len[0] = strlen(data[0]);
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+    data[1] = error->device_dependent_info;
+#if USE_MEMORY_ALLOCATION_FREE
+    len[1] = error->device_dependent_info ? strlen(data[1]) : 0;
+#else
+    SCPIDEFINE_get_parts(&context->error_info_heap, data[1], &len[1], &data[2], &len[2]);
+#endif
+#endif
+
+    result += SCPI_ResultInt32(context, error->error_code);
+    result += writeDelimiter(context);
+    result += writeData(context, "\"", 1);
+
+    for (i = 0; (i < SCPIDEFINE_DESCRIPTION_MAX_PARTS) && data[i] && outputlimit; i++) {
+        if (i == 1) {
+            result += writeSemicolon(context);
+            outputlimit -= 1;
+        }
+        if (len[i] > outputlimit) {
+            len[i] = outputlimit;
+        }
+
+        while ((quote = strnpbrk(data[i], len[i], "\""))) {
+            if ((step = quote - data[i] + 1) >= outputlimit) {
+                len[i] -= 1;
+                outputlimit -= 1;
+                break;
+            }
+            result += writeData(context, data[i], step);
+            result += writeData(context, "\"", 1);
+            len[i] -= step;
+            outputlimit -= step + 1;
+            data[i] = quote + 1;
+            if (len[i] > outputlimit) {
+                len[i] = outputlimit;
+            }
+        }
+
+        result += writeData(context, data[i], len[i]);
+        outputlimit -= len[i];
+    }
+    result += writeData(context, "\"", 1);
+
+    return result;
+}
+
+/**
  * Write arbitrary block header with length
  * @param context
  * @param len
diff --git a/libscpi/src/utils.c b/libscpi/src/utils.c
index dd8e042..cb34cc7 100644
--- a/libscpi/src/utils.c
+++ b/libscpi/src/utils.c
@@ -184,7 +184,7 @@
             case 8:
                 x = 0x8000000000000000ULL;
                 break;
-	    default:
+            default:
             case 10:
                 x = 10000000000000000000ULL;
                 base = 10;
@@ -750,6 +750,145 @@
 }
 #endif
 
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+
+/**
+ * Initialize heap structure
+ * @param heap - pointer to manual allocated heap buffer
+ * @param error_info_heap - buffer for the heap
+ * @param error_info_heap_length - length of the heap
+ */
+void scpiheap_init(scpi_error_info_heap_t * heap, char * error_info_heap, size_t error_info_heap_length)
+{
+    heap->data = error_info_heap;
+    heap->wr = 0;
+    heap->size = error_info_heap_length;
+    heap->count = heap->size;
+    memset(heap->data, 0, heap->size);
+}
+
+/**
+ * Duplicate string if "strdup" ("malloc/free") not supported on system.
+ * Allocate space in heap if it possible
+ *
+ * @param heap - pointer to manual allocated heap buffer
+ * @param s - current pointer of duplication string
+ * @return - pointer of duplicated string or NULL, if duplicate is not possible.
+ */
+char * scpiheap_strndup(scpi_error_info_heap_t * heap, const char *s, size_t n) {
+    if (!s || !heap || !heap->size) {
+        return NULL;
+    }
+
+    if (heap->data[heap->wr] != '\0') {
+        return NULL;
+    }
+
+    if (*s == '\0') {
+        return NULL;
+    }
+
+    size_t len = SCPIDEFINE_strnlen(s, n) + 1; // additional '\0' at end
+    if (len > heap->count) {
+        return NULL;
+    }
+    const char * ptrs = s;
+    char * head = &heap->data[heap->wr];
+    size_t rem = heap->size - (&heap->data[heap->wr] - heap->data);
+
+    if (len >= rem) {
+        memcpy(&heap->data[heap->wr], s, rem);
+        len = len - rem;
+        ptrs += rem;
+        heap->wr = 0;
+        heap->count -= rem;
+    }
+
+    memcpy(&heap->data[heap->wr], ptrs, len);
+    heap->wr += len;
+    heap->count -= len;
+
+    // ensure '\0' a the end
+    if (heap->wr > 0) {
+        heap->data[heap->wr - 1] = '\0';
+    } else {
+        heap->data[heap->size - 1] = '\0';
+    }
+    return head;
+}
+
+/**
+ * Return pointers and lengths two parts of string in the circular buffer from heap
+ *
+ * @param heap - pointer to manual allocated heap buffer
+ * @param s - pointer of duplicate string.
+ * @return len1 - lenght of first part of string.
+ * @return s2 - pointer of second part of string, if string splited .
+ * @return len2 - lenght of second part of string.
+ */
+scpi_bool_t scpiheap_get_parts(scpi_error_info_heap_t * heap, const char * s, size_t * len1, const char ** s2, size_t * len2) {
+    if (!heap || !s || !len1 || !s2 || !len2) {
+        return FALSE;
+    }
+
+    if (*s == '\0') {
+        return FALSE;
+    }
+
+    *len1 = 0;
+    size_t rem = heap->size - (s - heap->data);
+    *len1 = strnlen(s, rem);
+
+    if (&s[*len1 - 1] == &heap->data[heap->size - 1]) {
+        *s2 = heap->data;
+        *len2 = strnlen(*s2, heap->size);
+    } else {
+        *s2 = NULL;
+        *len2 = 0;
+    }
+    return TRUE;
+}
+
+/**
+ * Frees space in heap, if "malloc/free" not supported on system, or nothing.
+ *
+ * @param heap - pointer to manual allocated heap buffer
+ * @param s - pointer of duplicate string
+ * @param rollback - backward write pointer in heap
+ */
+void scpiheap_free(scpi_error_info_heap_t * heap, char * s, scpi_bool_t rollback) {
+
+    if (!s) return;
+
+    char * data_add;
+    size_t len[2];
+
+    if (!scpiheap_get_parts(heap, s, &len[0], (const char **)&data_add, &len[1])) return;
+
+    if (data_add) {
+        len[1]++;
+        memset(data_add, 0, len[1]);
+        heap->count += len[1];
+    } else {
+        len[0]++;
+    }
+    memset(s, 0, len[0]);
+    heap->count += len[0];
+    if (heap->count == heap->size) {
+        heap->wr = 0;
+        return;
+    }
+    if (rollback) {
+        size_t rb = len[0] + len[1];
+        if (rb > heap->wr) {
+            heap->wr += heap->size;
+        }
+        heap->wr -= rb;
+    }
+}
+
+#endif
+
 // Floating point to string conversion routines
 //
 // Copyright (C) 2002 Michael Ringgaard. All rights reserved.
@@ -810,7 +949,7 @@
             buf[--w2] = (int) ((fj + .03) * 10) + '0';
             r2++;
         }
-        while (w2 < (int)bufsize) buf[w1++] = buf[w2++];
+        while (w2 < (int) bufsize) buf[w1++] = buf[w2++];
     } else if (arg > 0) {
         while ((fj = arg * 10) < 1) {
             arg = fj;
@@ -823,12 +962,12 @@
         buf[0] = '\0';
         return buf;
     }
-    while (w1 <= w2 && w1 < (int)bufsize) {
+    while (w1 <= w2 && w1 < (int) bufsize) {
         arg *= 10;
         arg = modf(arg, &fj);
         buf[w1++] = (int) fj + '0';
     }
-    if (w2 >= (int)bufsize) {
+    if (w2 >= (int) bufsize) {
         buf[bufsize - 1] = '\0';
         return buf;
     }
@@ -934,9 +1073,10 @@
 
 /**
  * Get native CPU endiannes
- * @return 
+ * @return
  */
 scpi_array_format_t SCPI_GetNativeFormat(void) {
+
     union {
         uint32_t i;
         char c[4];
@@ -948,17 +1088,17 @@
 /**
  * Swap 16bit number
  * @param val
- * @return 
+ * @return
  */
 uint16_t SCPI_Swap16(uint16_t val) {
-    return ((val & 0x00FF) << 8) | 
+    return ((val & 0x00FF) << 8) |
             ((val & 0xFF00) >> 8);
 }
 
 /**
  * Swap 32bit number
  * @param val
- * @return 
+ * @return
  */
 uint32_t SCPI_Swap32(uint32_t val) {
     return ((val & 0x000000FF) << 24) |
@@ -970,7 +1110,7 @@
 /**
  * Swap 64bit number
  * @param val
- * @return 
+ * @return
  */
 uint64_t SCPI_Swap64(uint64_t val) {
     return ((val & 0x00000000000000FFul) << 56) |
diff --git a/libscpi/src/utils_private.h b/libscpi/src/utils_private.h
index 671dea0..ba1f8fc 100644
--- a/libscpi/src/utils_private.h
+++ b/libscpi/src/utils_private.h
@@ -87,6 +87,13 @@
     int OUR_strncasecmp(const char *s1, const char *s2, size_t n) LOCAL;
 #endif
 
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+    void scpiheap_init(scpi_error_info_heap_t * heap, char * error_info_heap, size_t error_info_heap_length);
+    char * scpiheap_strndup(scpi_error_info_heap_t * heap, const char *s, size_t n) LOCAL;
+    void scpiheap_free(scpi_error_info_heap_t * heap, char *s, scpi_bool_t rollback) LOCAL;
+    scpi_bool_t scpiheap_get_parts(scpi_error_info_heap_t * heap, const char *s1, size_t * len1, const char ** s2, size_t * len2) LOCAL;
+#endif
+
 #ifndef min
 #define min(a, b)  (((a) < (b)) ? (a) : (b))
 #endif
diff --git a/libscpi/test/test_fifo.c b/libscpi/test/test_fifo.c
index 40c65c5..546e0c8 100644
--- a/libscpi/test/test_fifo.c
+++ b/libscpi/test/test_fifo.c
@@ -25,14 +25,15 @@
 
 static void testFifo() {
     scpi_fifo_t fifo;
-    int16_t fifo_data[4];
+    scpi_error_t fifo_data[4];
     fifo_init(&fifo, fifo_data, 4);
-    int16_t value;
+    scpi_error_t value;
+    int16_t count_value;
 
 #define TEST_FIFO_COUNT(n)                      \
     do {                                        \
-        fifo_count(&fifo, &value);              \
-        CU_ASSERT_EQUAL(value, n);              \
+        fifo_count(&fifo, &count_value);        \
+        CU_ASSERT_EQUAL(count_value, n);        \
     } while(0)                                  \
 
 
@@ -40,95 +41,103 @@
     CU_ASSERT_TRUE(fifo_is_empty(&fifo));
     CU_ASSERT_FALSE(fifo_is_full(&fifo));
 
-    CU_ASSERT_TRUE(fifo_add(&fifo, 1));
+    value.error_code = 1;
+    CU_ASSERT_TRUE(fifo_add(&fifo, &value));
     TEST_FIFO_COUNT(1);
     CU_ASSERT_FALSE(fifo_is_empty(&fifo));
     CU_ASSERT_FALSE(fifo_is_full(&fifo));
 
-    CU_ASSERT_TRUE(fifo_add(&fifo, 2));
+    value.error_code = 2;
+    CU_ASSERT_TRUE(fifo_add(&fifo, &value));
     TEST_FIFO_COUNT(2);
     CU_ASSERT_FALSE(fifo_is_empty(&fifo));
     CU_ASSERT_FALSE(fifo_is_full(&fifo));
 
-    CU_ASSERT_TRUE(fifo_add(&fifo, 3));
+    value.error_code = 3;
+    CU_ASSERT_TRUE(fifo_add(&fifo, &value));
     TEST_FIFO_COUNT(3);
     CU_ASSERT_FALSE(fifo_is_empty(&fifo));
     CU_ASSERT_FALSE(fifo_is_full(&fifo));
 
-    CU_ASSERT_TRUE(fifo_add(&fifo, 4));
+    value.error_code = 4;
+    CU_ASSERT_TRUE(fifo_add(&fifo, &value));
     TEST_FIFO_COUNT(4);
     CU_ASSERT_FALSE(fifo_is_empty(&fifo));
     CU_ASSERT_TRUE(fifo_is_full(&fifo));
 
-    CU_ASSERT_EQUAL(fifo.data[0], 1);
-    CU_ASSERT_EQUAL(fifo.data[1], 2);
-    CU_ASSERT_EQUAL(fifo.data[2], 3);
-    CU_ASSERT_EQUAL(fifo.data[3], 4);
+    CU_ASSERT_EQUAL(fifo.data[0].error_code, 1);
+    CU_ASSERT_EQUAL(fifo.data[1].error_code, 2);
+    CU_ASSERT_EQUAL(fifo.data[2].error_code, 3);
+    CU_ASSERT_EQUAL(fifo.data[3].error_code, 4);
 
-
-    CU_ASSERT_FALSE(fifo_add(&fifo, 5));
+    value.error_code = 5;
+    CU_ASSERT_FALSE(fifo_add(&fifo, &value));
     TEST_FIFO_COUNT(4);
     CU_ASSERT_FALSE(fifo_is_empty(&fifo));
     CU_ASSERT_TRUE(fifo_is_full(&fifo));
 
-    CU_ASSERT_EQUAL(fifo.data[0], 1);
-    CU_ASSERT_EQUAL(fifo.data[1], 2);
-    CU_ASSERT_EQUAL(fifo.data[2], 3);
-    CU_ASSERT_EQUAL(fifo.data[3], 4);
+    CU_ASSERT_EQUAL(fifo.data[0].error_code, 1);
+    CU_ASSERT_EQUAL(fifo.data[1].error_code, 2);
+    CU_ASSERT_EQUAL(fifo.data[2].error_code, 3);
+    CU_ASSERT_EQUAL(fifo.data[3].error_code, 4);
 
     CU_ASSERT_TRUE(fifo_remove_last(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 4);
+    CU_ASSERT_EQUAL(value.error_code, 4);
     TEST_FIFO_COUNT(3);
     CU_ASSERT_FALSE(fifo_is_empty(&fifo));
     CU_ASSERT_FALSE(fifo_is_full(&fifo));
 
-    CU_ASSERT_TRUE(fifo_add(&fifo, 6));
+    value.error_code = 6;
+    CU_ASSERT_TRUE(fifo_add(&fifo, &value));
     TEST_FIFO_COUNT(4);
     CU_ASSERT_FALSE(fifo_is_empty(&fifo));
     CU_ASSERT_TRUE(fifo_is_full(&fifo));
 
-    CU_ASSERT_EQUAL(fifo.data[0], 1);
-    CU_ASSERT_EQUAL(fifo.data[1], 2);
-    CU_ASSERT_EQUAL(fifo.data[2], 3);
-    CU_ASSERT_EQUAL(fifo.data[3], 6);
+    CU_ASSERT_EQUAL(fifo.data[0].error_code, 1);
+    CU_ASSERT_EQUAL(fifo.data[1].error_code, 2);
+    CU_ASSERT_EQUAL(fifo.data[2].error_code, 3);
+    CU_ASSERT_EQUAL(fifo.data[3].error_code, 6);
 
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 1);
+    CU_ASSERT_EQUAL(value.error_code, 1);
     TEST_FIFO_COUNT(3);
     CU_ASSERT_FALSE(fifo_is_empty(&fifo));
     CU_ASSERT_FALSE(fifo_is_full(&fifo));
 
-    CU_ASSERT_TRUE(fifo_add(&fifo, 7));
+    value.error_code = 7;
+    CU_ASSERT_TRUE(fifo_add(&fifo, &value));
     TEST_FIFO_COUNT(4);
 
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 2);
+    CU_ASSERT_EQUAL(value.error_code, 2);
     TEST_FIFO_COUNT(3);
 
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 3);
+    CU_ASSERT_EQUAL(value.error_code, 3);
     TEST_FIFO_COUNT(2);
 
-    CU_ASSERT_TRUE(fifo_add(&fifo, 10));
+    value.error_code = 10;
+    CU_ASSERT_TRUE(fifo_add(&fifo, &value));
     TEST_FIFO_COUNT(3);
 
-    CU_ASSERT_TRUE(fifo_add(&fifo, 11));
+    value.error_code = 11;
+    CU_ASSERT_TRUE(fifo_add(&fifo, &value));
     TEST_FIFO_COUNT(4);
 
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 6);
+    CU_ASSERT_EQUAL(value.error_code, 6);
     TEST_FIFO_COUNT(3);
 
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 7);
+    CU_ASSERT_EQUAL(value.error_code, 7);
     TEST_FIFO_COUNT(2);
 
     CU_ASSERT_TRUE(fifo_remove_last(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 11);
+    CU_ASSERT_EQUAL(value.error_code, 11);
     TEST_FIFO_COUNT(1);
 
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 10);
+    CU_ASSERT_EQUAL(value.error_code, 10);
     TEST_FIFO_COUNT(0);
 
     CU_ASSERT_FALSE(fifo_remove(&fifo, &value));
diff --git a/libscpi/test/test_parser.c b/libscpi/test/test_parser.c
index 580a721..ad5194a 100644
--- a/libscpi/test/test_parser.c
+++ b/libscpi/test/test_parser.c
@@ -184,7 +184,10 @@
 static char scpi_input_buffer[SCPI_INPUT_BUFFER_LENGTH];
 
 #define SCPI_ERROR_QUEUE_SIZE 4
-static int16_t scpi_error_queue_data[SCPI_ERROR_QUEUE_SIZE];
+static scpi_error_t scpi_error_queue_data[SCPI_ERROR_QUEUE_SIZE];
+
+#define SCPI_ERROR_INFO_HEAP_SIZE 16
+static char error_info_heap[SCPI_ERROR_INFO_HEAP_SIZE];
 
 static int init_suite(void) {
     SCPI_Init(&scpi_context,
@@ -194,6 +197,10 @@
             "MA", "IN", NULL, "VER",
             scpi_input_buffer, SCPI_INPUT_BUFFER_LENGTH,
             scpi_error_queue_data, SCPI_ERROR_QUEUE_SIZE);
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+    SCPI_InitHeap(&scpi_context,
+            error_info_heap, SCPI_ERROR_INFO_HEAP_SIZE);
+#endif
 
     return 0;
 }
@@ -285,6 +292,55 @@
     error_buffer_clear();
 }
 
+static void testErrorHandlingDeviceDependent(void) {
+#define TEST_CMDERR(output) {\
+    SCPI_Input(&scpi_context, "SYST:ERR:NEXT?\r\n", strlen("SYST:ERR:NEXT?\r\n"));\
+    CU_ASSERT_STRING_EQUAL(output, output_buffer);\
+    output_buffer_clear();\
+}
+
+    output_buffer_clear();
+    error_buffer_clear();
+
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, "Test1", 0);
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, NULL, 0);
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, NULL, 0);
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, "Test4", 0);
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, "Test5", 0);
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+    TEST_CMDERR("-101,\"Invalid character;Test1\"\r\n");
+#else /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */
+    TEST_CMDERR("-101,\"Invalid character\"\r\n");
+#endif /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */
+    TEST_CMDERR("-101,\"Invalid character\"\r\n");
+    TEST_CMDERR("-101,\"Invalid character\"\r\n");
+    TEST_CMDERR("-350,\"Queue overflow\"\r\n");
+    TEST_CMDERR("0,\"No error\"\r\n");
+
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, "Test6", 0);
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, "Test7", 0);
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, "Test8", 0);
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, "Test9", 0);
+    SCPI_ErrorPushEx(&scpi_context, SCPI_ERROR_INVALID_CHARACTER, "Test10", 0);
+
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+    TEST_CMDERR("-101,\"Invalid character;Test6\"\r\n");
+    TEST_CMDERR("-101,\"Invalid character;Test7\"\r\n");
+#if USE_MEMORY_ALLOCATION_FREE
+    TEST_CMDERR("-101,\"Invalid character;Test8\"\r\n");
+#else /* USE_MEMORY_ALLOCATION_FREE */
+    TEST_CMDERR("-101,\"Invalid character\"\r\n");
+#endif /* USE_MEMORY_ALLOCATION_FREE */
+#else /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */
+    TEST_CMDERR("-101,\"Invalid character\"\r\n");
+    TEST_CMDERR("-101,\"Invalid character\"\r\n");
+    TEST_CMDERR("-101,\"Invalid character\"\r\n");
+#endif /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */
+    TEST_CMDERR("-350,\"Queue overflow\"\r\n");
+    TEST_CMDERR("0,\"No error\"\r\n");
+}
+
 static void testIEEE4882(void) {
 #define TEST_IEEE4882(data, output) {                           \
     SCPI_Input(&scpi_context, data, strlen(data));              \
@@ -327,7 +383,11 @@
     TEST_IEEE4882("*ESR?\r\n", "0\r\n");
 
     TEST_IEEE4882("SYST:ERR:COUNT?\r\n", "1\r\n");
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+    TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "-113,\"Undefined header;ABCD\"\r\n");
+#else /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */
     TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "-113,\"Undefined header\"\r\n");
+#endif /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */
     TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "0,\"No error\"\r\n");
 
     TEST_IEEE4882("*STB?\r\n", "0\r\n"); /* Error queue is now empty */
@@ -338,7 +398,11 @@
     CU_ASSERT_EQUAL(srq_val, 0); /* no control callback */
     TEST_IEEE4882("*STB?\r\n", "100\r\n"); /* Event status register + Service request */
     TEST_IEEE4882("*ESR?\r\n", "32\r\n"); /* Command error */
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION
+    TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "-113,\"Undefined header;ABCD\"\r\n");
+#else /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */
     TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "-113,\"Undefined header\"\r\n");
+#endif /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */
     scpi_context.interface->control = SCPI_Control;
 
     RST_executed = FALSE;
@@ -387,7 +451,7 @@
 {                                                                                       \
     int32_t value;                                                                      \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -396,12 +460,12 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamInt32(&scpi_context, &value, mandatory);                         \
                                                                                         \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_EQUAL(value, expected_value);                                         \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testSCPI_ParamInt32(void) {
@@ -426,7 +490,7 @@
 {                                                                                       \
     uint32_t value;                                                                     \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -435,12 +499,12 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamUInt32(&scpi_context, &value, mandatory);                        \
                                                                                         \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_EQUAL(value, expected_value);                                         \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testSCPI_ParamUInt32(void) {
@@ -465,7 +529,7 @@
 {                                                                                       \
     int64_t value;                                                                      \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -474,12 +538,12 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamInt64(&scpi_context, &value, mandatory);                         \
                                                                                         \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_EQUAL(value, expected_value);                                         \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testSCPI_ParamInt64(void) {
@@ -506,7 +570,7 @@
 {                                                                                       \
     uint64_t value;                                                                     \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -515,12 +579,12 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamUInt64(&scpi_context, &value, mandatory);                        \
                                                                                         \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_EQUAL(value, expected_value);                                         \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testSCPI_ParamUInt64(void) {
@@ -548,7 +612,7 @@
 {                                                                                       \
     float value;                                                                        \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -557,12 +621,12 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamFloat(&scpi_context, &value, mandatory);                         \
                                                                                         \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_DOUBLE_EQUAL(value, expected_value, 0.000001);                        \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testSCPI_ParamFloat(void) {
@@ -584,7 +648,7 @@
 {                                                                                       \
     double value;                                                                       \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -593,12 +657,12 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamDouble(&scpi_context, &value, mandatory);                        \
                                                                                         \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_DOUBLE_EQUAL(value, expected_value, 0.000001);                        \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testSCPI_ParamDouble(void) {
@@ -621,7 +685,7 @@
     const char * value;                                                                 \
     size_t value_len;                                                                   \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -630,12 +694,12 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamCharacters(&scpi_context, &value, &value_len, mandatory);        \
     /*printf("%.*s\r\n",  (int)value_len, value);*/                                     \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_NSTRING_EQUAL(value, expected_value, value_len);                      \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testSCPI_ParamCharacters(void) {
@@ -653,7 +717,7 @@
     char value[100];                                                                    \
     size_t value_len;                                                                   \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -662,13 +726,13 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamCopyText(&scpi_context, value, sizeof(value), &value_len, mandatory);\
     /*printf("%.*s\r\n",  (int)value_len, value);*/                                     \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_STRING_EQUAL(value, expected_value);                                  \
         CU_ASSERT_EQUAL(value_len, expected_len);                                       \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testSCPI_ParamCopyText(void) {
@@ -689,21 +753,21 @@
     const char * value;                                                                 \
     size_t value_len;                                                                   \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
     scpi_context.param_list.lex_state.buffer = data;                                    \
     scpi_context.param_list.lex_state.len = strlen(scpi_context.param_list.lex_state.buffer);\
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
-    result = SCPI_ParamArbitraryBlock(&scpi_context, &value, &value_len, mandatory);        \
+    result = SCPI_ParamArbitraryBlock(&scpi_context, &value, &value_len, mandatory);    \
     /*printf("%.*s\r\n",  (int)value_len, value);*/                                     \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_NSTRING_EQUAL(value, expected_value, value_len);                      \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 static void testSCPI_ParamArbitraryBlock(void) {
     TEST_ParamArbitraryBlock("#204ABCD", TRUE, "ABCD", TRUE, 0);
@@ -714,21 +778,21 @@
 {                                                                                       \
     scpi_bool_t value;                                                                  \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
     scpi_context.param_list.lex_state.buffer = data;                                    \
     scpi_context.param_list.lex_state.len = strlen(scpi_context.param_list.lex_state.buffer);\
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
-    result = SCPI_ParamBool(&scpi_context, &value, mandatory);                         \
+    result = SCPI_ParamBool(&scpi_context, &value, mandatory);                          \
                                                                                         \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_EQUAL(value, expected_value);                                         \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 static void testSCPI_ParamBool(void) {
     TEST_ParamBool("ON", TRUE, TRUE, TRUE, 0);
@@ -743,7 +807,7 @@
 {                                                                                       \
     int32_t value;                                                                      \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -752,12 +816,12 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamChoice(&scpi_context, test_options, &value, mandatory);          \
                                                                                         \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_EQUAL(value, expected_value);                                         \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 static void testSCPI_ParamChoice(void) {
     scpi_choice_def_t test_options[] = {
@@ -778,7 +842,7 @@
 {                                                                                       \
     scpi_bool_t result;                                                                 \
     scpi_expr_result_t result2;                                                         \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
     scpi_parameter_t param;                                                             \
     int32_t val_from, val_to;                                                           \
     scpi_bool_t val_range;                                                              \
@@ -790,7 +854,7 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_Parameter(&scpi_context, &param, TRUE);                               \
     result2 = SCPI_ExprNumericListEntryInt(&scpi_context, &param, index, &val_range, &val_from, &val_to);\
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result2, expected_result);                                          \
     if (expected_result == SCPI_EXPR_OK) {                                              \
         CU_ASSERT_EQUAL(val_range, expected_range);                                     \
@@ -799,14 +863,14 @@
             CU_ASSERT_EQUAL(val_to, expected_to);                                       \
         }                                                                               \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 #define TEST_NumericListDouble(data, index, expected_range, expected_from, expected_to, expected_result, expected_error_code) \
 {                                                                                       \
     scpi_bool_t result;                                                                 \
     scpi_expr_result_t result2;                                                         \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
     scpi_parameter_t param;                                                             \
     double val_from, val_to;                                                            \
     scpi_bool_t val_range;                                                              \
@@ -818,7 +882,7 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_Parameter(&scpi_context, &param, TRUE);                               \
     result2 = SCPI_ExprNumericListEntryDouble(&scpi_context, &param, index, &val_range, &val_from, &val_to);\
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result2, expected_result);                                          \
     if (expected_result == SCPI_EXPR_OK) {                                              \
         CU_ASSERT_EQUAL(val_range, expected_range);                                     \
@@ -827,7 +891,7 @@
             CU_ASSERT_DOUBLE_EQUAL(val_to, expected_to, 0.0001);                        \
         }                                                                               \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testNumericList(void) {
@@ -864,7 +928,7 @@
 {                                                                                       \
     scpi_bool_t result;                                                                 \
     scpi_expr_result_t result2;                                                         \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
     scpi_parameter_t param;                                                             \
     int32_t val_from[val_len], val_to[val_len];                                         \
     scpi_bool_t val_range;                                                              \
@@ -879,7 +943,7 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_Parameter(&scpi_context, &param, TRUE);                               \
     result2 = SCPI_ExprChannelListEntry(&scpi_context, &param, index, &val_range, val_from, val_to, val_len, &val_dimensions);\
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result2, expected_result);                                          \
     if (expected_result == SCPI_EXPR_OK) {                                              \
         CU_ASSERT_EQUAL(val_dimensions, expected_dimensions);                           \
@@ -893,7 +957,7 @@
             }}                                                                          \
         }                                                                               \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testChannelList(void) {
@@ -935,7 +999,7 @@
 {                                                                                       \
     scpi_number_t value;                                                                \
     scpi_bool_t result;                                                                 \
-    int16_t errCode;                                                                    \
+    scpi_error_t errCode;                                                               \
                                                                                         \
     SCPI_CoreCls(&scpi_context);                                                        \
     scpi_context.input_count = 0;                                                       \
@@ -944,7 +1008,7 @@
     scpi_context.param_list.lex_state.pos = scpi_context.param_list.lex_state.buffer;   \
     result = SCPI_ParamNumber(&scpi_context, scpi_special_numbers_def, &value, mandatory);\
                                                                                         \
-    errCode = SCPI_ErrorPop(&scpi_context);                                             \
+    SCPI_ErrorPop(&scpi_context, &errCode);                                             \
     CU_ASSERT_EQUAL(result, expected_result);                                           \
     if (expected_result) {                                                              \
         CU_ASSERT_EQUAL(value.special, expected_special);                               \
@@ -953,7 +1017,7 @@
         CU_ASSERT_EQUAL(value.unit, expected_unit);                                     \
         CU_ASSERT_EQUAL(value.base, expected_base);                                     \
     }                                                                                   \
-    CU_ASSERT_EQUAL(errCode, expected_error_code);                                      \
+    CU_ASSERT_EQUAL(errCode.error_code, expected_error_code);                           \
 }
 
 static void testParamNumber(void) {
@@ -1282,6 +1346,7 @@
 }
 
 static void testErrorQueue(void) {
+    scpi_error_t val;
     SCPI_ErrorClear(&scpi_context);
     CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 0);
     SCPI_ErrorPush(&scpi_context, -1);
@@ -1297,15 +1362,20 @@
     SCPI_ErrorPush(&scpi_context, -6);
     CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 4);
 
-    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), -1);
+    SCPI_ErrorPop(&scpi_context, &val);
+    CU_ASSERT_EQUAL(val.error_code, -1);
     CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 3);
-    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), -2);
+    SCPI_ErrorPop(&scpi_context, &val);
+    CU_ASSERT_EQUAL(val.error_code, -2);
     CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 2);
-    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), -3);
+    SCPI_ErrorPop(&scpi_context, &val);
+    CU_ASSERT_EQUAL(val.error_code, -3);
     CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 1);
-    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), SCPI_ERROR_QUEUE_OVERFLOW);
+    SCPI_ErrorPop(&scpi_context, &val);
+    CU_ASSERT_EQUAL(val.error_code, SCPI_ERROR_QUEUE_OVERFLOW);
     CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 0);
-    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), 0);
+    SCPI_ErrorPop(&scpi_context, &val);
+    CU_ASSERT_EQUAL(val.error_code, 0);
     CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 0);
 
     SCPI_ErrorClear(&scpi_context);
@@ -1461,6 +1531,7 @@
             || (NULL == CU_add_test(pSuite, "SCPI_ParamChoice", testSCPI_ParamChoice))
             || (NULL == CU_add_test(pSuite, "Commands handling", testCommandsHandling))
             || (NULL == CU_add_test(pSuite, "Error handling", testErrorHandling))
+            || (NULL == CU_add_test(pSuite, "Device dependent error handling", testErrorHandlingDeviceDependent))
             || (NULL == CU_add_test(pSuite, "IEEE 488.2 Mandatory commands", testIEEE4882))
             || (NULL == CU_add_test(pSuite, "Numeric list", testNumericList))
             || (NULL == CU_add_test(pSuite, "Channel list", testChannelList))
diff --git a/libscpi/test/test_scpi_utils.c b/libscpi/test/test_scpi_utils.c
index 98a7305..83d7fb0 100644
--- a/libscpi/test/test_scpi_utils.c
+++ b/libscpi/test/test_scpi_utils.c
@@ -744,6 +744,61 @@
     TEST_SWAP(64, 0x123456789ABCDEF0ull, 0xF0DEBC9A78563412ull);
 }
 
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+
+static void test_heap(void) {
+
+#define ERROR_INFO_HEAP_LENGTH  16
+    scpi_error_info_heap_t heap;
+    char error_info_heap[ERROR_INFO_HEAP_LENGTH];
+
+    scpiheap_init(&heap, error_info_heap, ERROR_INFO_HEAP_LENGTH);
+    CU_ASSERT_EQUAL(heap.size, ERROR_INFO_HEAP_LENGTH);
+    CU_ASSERT_EQUAL(heap.data, error_info_heap);
+    CU_ASSERT_EQUAL(heap.count, heap.size);
+
+    char * ptr1 = scpiheap_strndup(&heap, "abcd", 4);
+    CU_ASSERT_STRING_EQUAL(ptr1, "abcd");
+
+    char * ptr2 = scpiheap_strndup(&heap, "xyz", 3);
+    CU_ASSERT_STRING_EQUAL(ptr2, "xyz");
+
+    char * ptr3 = scpiheap_strndup(&heap, "ghijklmnop", 10);
+    CU_ASSERT_EQUAL(ptr3, NULL);
+
+    scpiheap_free(&heap, ptr1, false);
+
+    char * ptr4 = scpiheap_strndup(&heap, "ghijklmnop", 10);
+    CU_ASSERT_NOT_EQUAL(ptr4, NULL);
+
+    const char * ptr5;
+    size_t len1, len2;
+    CU_ASSERT_EQUAL(scpiheap_get_parts(&heap, ptr4, &len1, &ptr5, &len2), TRUE);
+    CU_ASSERT_EQUAL(len1, 7);
+    CU_ASSERT_EQUAL(len2, 3);
+    CU_ASSERT_STRING_EQUAL(ptr5, "nop");
+    CU_ASSERT_EQUAL(memcmp(ptr4, "ghijklm", len1), 0);
+
+    scpiheap_free(&heap, ptr2, false);
+
+    char * ptr6 = scpiheap_strndup(&heap, "abcd", 4);
+    CU_ASSERT_STRING_EQUAL(ptr6, "abcd");
+
+    scpiheap_free(&heap, ptr6, true);
+
+    char * ptr7 = scpiheap_strndup(&heap, "123456789", 9);
+    CU_ASSERT_EQUAL(ptr7, NULL);
+
+    char * ptr8 = scpiheap_strndup(&heap, "123456789", 4);
+    CU_ASSERT_STRING_EQUAL(ptr8, "1234");
+
+    scpiheap_free(&heap, ptr4, false);
+    scpiheap_free(&heap, ptr8, false);
+    CU_ASSERT_EQUAL(heap.count, heap.size);
+
+}
+#endif
+
 int main() {
     unsigned int result;
     CU_pSuite pSuite = NULL;
@@ -780,6 +835,9 @@
             || (NULL == CU_add_test(pSuite, "matchCommand", test_matchCommand))
             || (NULL == CU_add_test(pSuite, "composeCompoundCommand", test_composeCompoundCommand))
             || (NULL == CU_add_test(pSuite, "swap", test_swap))
+#if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE
+            || (NULL == CU_add_test(pSuite, "heap", test_heap))
+#endif
             ) {
         CU_cleanup_registry();
         return CU_get_error();

--
Gitblit v1.9.1