From 540dc9643efc866af6e7040634c9d7a17ca6c5b0 Mon Sep 17 00:00:00 2001
From: Jan Breuer <jan.breuer@jaybee.cz>
Date: 周六, 05 12月 2015 21:40:52 +0800
Subject: [PATCH] Fix error queue and resolve #67

---
 libscpi/inc/scpi/error.h   |    2 
 libscpi/src/fifo_private.h |    3 
 libscpi/src/error.c        |   37 +--------
 libscpi/src/fifo.c         |   57 ++++++++++++--
 libscpi/test/test_parser.c |   43 +++++++++-
 libscpi/test/test_fifo.c   |   77 ++++++++++++++++--
 6 files changed, 162 insertions(+), 57 deletions(-)

diff --git a/libscpi/inc/scpi/error.h b/libscpi/inc/scpi/error.h
index 539ebae..c8f9679 100644
--- a/libscpi/inc/scpi/error.h
+++ b/libscpi/inc/scpi/error.h
@@ -164,7 +164,7 @@
     XE(SCPI_ERROR_OUT_OF_DEVICE_MEMORY,         -321, "Out of memory")                                \
     XE(SCPI_ERROR_SELF_TEST_FAILED,             -330, "Self-test failed")                             \
     XE(SCPI_ERROR_CALIBRATION_FAILED,           -340, "Calibration failed")                           \
-    XE(SCPI_ERROR_QUEUE_OVERFLOW,               -350, "Queue overflow")                               \
+    X(SCPI_ERROR_QUEUE_OVERFLOW,                -350, "Queue overflow")                               \
     XE(SCPI_ERROR_COMMUNICATION_ERROR,          -360, "Communication error")                          \
     XE(SCPI_ERROR_PARITY_ERROR_IN_CMD_MSG,      -361, "Parity error in program message")              \
     XE(SCPI_ERROR_FRAMING_ERROR_IN_CMD_MSG,     -362, "Framing error in program message")             \
diff --git a/libscpi/src/error.c b/libscpi/src/error.c
index df3db2c..c0ef488 100644
--- a/libscpi/src/error.c
+++ b/libscpi/src/error.c
@@ -49,12 +49,6 @@
  * @param context - scpi context
  */
 void SCPI_ErrorInit(scpi_t * context) {
-    /*
-     * // FreeRTOS
-     * context->error_queue = (scpi_error_queue_t)xQueueCreate(100, sizeof(int16_t));
-     */
-
-    /* basic FIFO */
     context->error_queue = (scpi_error_queue_t) & local_error_queue;
     fifo_init((scpi_fifo_t *) context->error_queue);
 }
@@ -91,12 +85,6 @@
  * @param context - scpi context
  */
 void SCPI_ErrorClear(scpi_t * context) {
-    /*
-     * // FreeRTOS
-     * xQueueReset((xQueueHandle)context->error_queue);
-     */
-
-    /* basic FIFO */
     fifo_clear((scpi_fifo_t *) context->error_queue);
 
     SCPI_ErrorEmitEmpty(context);
@@ -110,14 +98,6 @@
 int16_t SCPI_ErrorPop(scpi_t * context) {
     int16_t result = 0;
 
-    /*
-     * // FreeRTOS
-     * if (pdFALSE == xQueueReceive((xQueueHandle)context->error_queue, &result, 0)) {
-     *   result = 0;
-     * }
-     */
-
-    /* basic FIFO */
     fifo_remove((scpi_fifo_t *) context->error_queue, &result);
 
     SCPI_ErrorEmitEmpty(context);
@@ -133,25 +113,16 @@
 int32_t SCPI_ErrorCount(scpi_t * context) {
     int16_t result = 0;
 
-    /*
-     * // FreeRTOS
-     * result = uxQueueMessagesWaiting((xQueueHandle)context->error_queue);
-     */
-
-    /* basic FIFO */
     fifo_count((scpi_fifo_t *) context->error_queue, &result);
 
     return result;
 }
 
 static void SCPI_ErrorAddInternal(scpi_t * context, int16_t err) {
-    /*
-     * // FreeRTOS
-     * xQueueSend((xQueueHandle)context->error_queue, &err, 0);
-     */
-
-    /* basic FIFO */
-    fifo_add((scpi_fifo_t *) context->error_queue, err);
+    if (!fifo_add((scpi_fifo_t *) context->error_queue, err)) {
+        fifo_remove_last((scpi_fifo_t *) context->error_queue, NULL);
+        fifo_add((scpi_fifo_t *) context->error_queue, SCPI_ERROR_QUEUE_OVERFLOW);
+    }
 }
 
 struct error_reg {
diff --git a/libscpi/src/fifo.c b/libscpi/src/fifo.c
index a69cf85..a64d351 100644
--- a/libscpi/src/fifo.c
+++ b/libscpi/src/fifo.c
@@ -21,19 +21,37 @@
 }
 
 /**
- * Add element to fifo. If fifo is full, remove last element.
+ * Test if fifo is empty
+ * @param fifo
+ * @return
+ */
+scpi_bool_t fifo_is_empty(scpi_fifo_t * fifo) {
+    return fifo->wr == fifo->rd;
+}
+
+/**
+ * Test if fifo is full
+ * @param fifo
+ * @return
+ */
+scpi_bool_t fifo_is_full(scpi_fifo_t * fifo) {
+    return fifo->wr == ((fifo->rd + fifo->size - 1) % (fifo->size));
+}
+
+/**
+ * Add element to fifo. If fifo is full, return FALSE.
  * @param fifo
  * @param value
- * @return 
+ * @return
  */
 scpi_bool_t fifo_add(scpi_fifo_t * fifo, int16_t value) {
     /* FIFO full? */
-    if (fifo->wr == ((fifo->rd + fifo->size) % (fifo->size + 1))) {
-        fifo_remove(fifo, NULL);
+    if (fifo_is_full(fifo)) {
+        return FALSE;
     }
 
     fifo->data[fifo->wr] = value;
-    fifo->wr = (fifo->wr + 1) % (fifo->size + 1);
+    fifo->wr = (fifo->wr + 1) % (fifo->size);
 
     return TRUE;
 }
@@ -46,7 +64,7 @@
  */
 scpi_bool_t fifo_remove(scpi_fifo_t * fifo, int16_t * value) {
     /* FIFO empty? */
-    if (fifo->wr == fifo->rd) {
+    if (fifo_is_empty(fifo)) {
         return FALSE;
     }
 
@@ -54,7 +72,28 @@
         *value = fifo->data[fifo->rd];
     }
 
-    fifo->rd = (fifo->rd + 1) % (fifo->size + 1);
+    fifo->rd = (fifo->rd + 1) % (fifo->size);
+
+    return TRUE;
+}
+
+/**
+ * Remove last element from fifo
+ * @param fifo
+ * @param value
+ * @return FALSE - fifo is empty
+ */
+scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, int16_t * value) {
+    /* FIFO empty? */
+    if (fifo_is_empty(fifo)) {
+        return FALSE;
+    }
+
+    fifo->wr = (fifo->wr + fifo->size - 1) % (fifo->size);
+
+    if (value) {
+        *value = fifo->data[fifo->wr];
+    }
 
     return TRUE;
 }
@@ -63,12 +102,12 @@
  * Retrive number of elements in fifo
  * @param fifo
  * @param value
- * @return 
+ * @return
  */
 scpi_bool_t fifo_count(scpi_fifo_t * fifo, int16_t * value) {
     *value = fifo->wr - fifo->rd;
     if (*value < 0) {
-        *value += (fifo->size + 1);
+        *value += (fifo->size);
     }
     return TRUE;
 }
diff --git a/libscpi/src/fifo_private.h b/libscpi/src/fifo_private.h
index 20dff74..d04da84 100644
--- a/libscpi/src/fifo_private.h
+++ b/libscpi/src/fifo_private.h
@@ -57,8 +57,11 @@
 
     void fifo_init(scpi_fifo_t * fifo) 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_count(scpi_fifo_t * fifo, int16_t * value) LOCAL;
 
 #ifdef	__cplusplus
diff --git a/libscpi/test/test_fifo.c b/libscpi/test/test_fifo.c
index c31cc26..f99a467 100644
--- a/libscpi/test/test_fifo.c
+++ b/libscpi/test/test_fifo.c
@@ -28,57 +28,114 @@
     fifo_init(&fifo);
     int16_t value;
 
-    fifo.size = 4;
+    fifo.size = 5;
 
 #define TEST_FIFO_COUNT(n)                      \
     do {                                        \
         fifo_count(&fifo, &value);              \
         CU_ASSERT_EQUAL(value, n);              \
     } while(0)                                  \
-    
+
 
     TEST_FIFO_COUNT(0);
+    CU_ASSERT_TRUE(fifo_is_empty(&fifo));
+    CU_ASSERT_FALSE(fifo_is_full(&fifo));
+
     CU_ASSERT_TRUE(fifo_add(&fifo, 1));
     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));
     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));
     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));
     TEST_FIFO_COUNT(4);
-    CU_ASSERT_TRUE(fifo_add(&fifo, 1));
-    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_FALSE(fifo_add(&fifo, 5));
+    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_TRUE(fifo_remove_last(&fifo, &value));
+    CU_ASSERT_EQUAL(value, 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));
+    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_TRUE(fifo_remove(&fifo, &value));
+    CU_ASSERT_EQUAL(value, 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));
+    TEST_FIFO_COUNT(4);
+
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
     CU_ASSERT_EQUAL(value, 2);
     TEST_FIFO_COUNT(3);
 
-    CU_ASSERT_TRUE(fifo_add(&fifo, 5));
+    CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
+    CU_ASSERT_EQUAL(value, 3);
+    TEST_FIFO_COUNT(2);
+
+    CU_ASSERT_TRUE(fifo_add(&fifo, 10));
+    TEST_FIFO_COUNT(3);
+
+    CU_ASSERT_TRUE(fifo_add(&fifo, 11));
     TEST_FIFO_COUNT(4);
 
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 3);
+    CU_ASSERT_EQUAL(value, 6);
     TEST_FIFO_COUNT(3);
 
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 4);
+    CU_ASSERT_EQUAL(value, 7);
     TEST_FIFO_COUNT(2);
 
-    CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 1);
+    CU_ASSERT_TRUE(fifo_remove_last(&fifo, &value));
+    CU_ASSERT_EQUAL(value, 11);
     TEST_FIFO_COUNT(1);
 
     CU_ASSERT_TRUE(fifo_remove(&fifo, &value));
-    CU_ASSERT_EQUAL(value, 5);
+    CU_ASSERT_EQUAL(value, 10);
     TEST_FIFO_COUNT(0);
 
     CU_ASSERT_FALSE(fifo_remove(&fifo, &value));
     TEST_FIFO_COUNT(0);
+
+    CU_ASSERT_FALSE(fifo_remove_last(&fifo, NULL));
 }
 
 int main() {
diff --git a/libscpi/test/test_parser.c b/libscpi/test/test_parser.c
index 0c59bfa..b3c1463 100644
--- a/libscpi/test/test_parser.c
+++ b/libscpi/test/test_parser.c
@@ -8,6 +8,7 @@
 #include "CUnit/Basic.h"
 
 #include "scpi/scpi.h"
+#include "../src/fifo_private.h"
 
 /*
  * CUnit Test Suite
@@ -316,7 +317,7 @@
     TEST_IEEE4882("ABCD\r\n", ""); /* "Undefined header" cause command error */
     CU_ASSERT_EQUAL(srq_val, (STB_ESR | STB_SRQ | STB_QMA)); /* value of STB as service request */
     TEST_IEEE4882("*STB?\r\n", "100\r\n"); /* Event status register + Service request */
-    TEST_IEEE4882("*ESR?\r\n", "32\r\n"); /* Command error */        
+    TEST_IEEE4882("*ESR?\r\n", "32\r\n"); /* Command error */
 
     TEST_IEEE4882("*STB?\r\n", "68\r\n"); /* Error queue is still not empty */
     TEST_IEEE4882("*ESR?\r\n", "0\r\n");
@@ -332,10 +333,10 @@
     TEST_IEEE4882("ABCD\r\n", ""); /* "Undefined header" cause command error */
     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 */        
+    TEST_IEEE4882("*ESR?\r\n", "32\r\n"); /* Command error */
     TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "-113,\"Undefined header\"\r\n");
     scpi_context.interface->control = SCPI_Control;
-    
+
     RST_executed = FALSE;
     TEST_IEEE4882("*RST\r\n", "");
     CU_ASSERT_EQUAL(RST_executed, TRUE);
@@ -372,7 +373,7 @@
 
     TEST_IEEE4882("STUB\r\n", "");
     TEST_IEEE4882("STUB?\r\n", "0\r\n");
-    
+
     TEST_IEEE4882_REG(SCPI_REG_COUNT + 1, 0);
     TEST_IEEE4882_REG_SET(SCPI_REG_OPERE, 1);
     TEST_IEEE4882_REG(SCPI_REG_OPERE, 1);
@@ -1180,6 +1181,39 @@
     TEST_SCPI_NumberToStr(TRUE, SCPI_NUM_DEF, SCPI_UNIT_NONE, "DEFault");
 }
 
+static void testErrorQueue(void) {
+    ((scpi_fifo_t *) (scpi_context.error_queue))->size = 5;
+
+    SCPI_ErrorClear(&scpi_context);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 0);
+    SCPI_ErrorPush(&scpi_context, -1);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 1);
+    SCPI_ErrorPush(&scpi_context, -2);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 2);
+    SCPI_ErrorPush(&scpi_context, -3);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 3);
+    SCPI_ErrorPush(&scpi_context, -4);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 4);
+    SCPI_ErrorPush(&scpi_context, -5);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 4);
+    SCPI_ErrorPush(&scpi_context, -6);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 4);
+
+    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), -1);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 3);
+    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), -2);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 2);
+    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), -3);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 1);
+    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), SCPI_ERROR_QUEUE_OVERFLOW);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 0);
+    CU_ASSERT_EQUAL(SCPI_ErrorPop(&scpi_context), 0);
+    CU_ASSERT_EQUAL(SCPI_ErrorCount(&scpi_context), 0);
+
+    SCPI_ErrorClear(&scpi_context);
+    ((scpi_fifo_t *) (scpi_context.error_queue))->size = FIFO_SIZE;
+}
+
 int main() {
     unsigned int result;
     CU_pSuite pSuite = NULL;
@@ -1226,6 +1260,7 @@
             || (NULL == CU_add_test(pSuite, "SCPI_ResultArbitraryBlock", testResultArbitraryBlock))
             || (NULL == CU_add_test(pSuite, "SCPI_ResultArray", testResultArray))
             || (NULL == CU_add_test(pSuite, "SCPI_NumberToStr", testNumberToStr))
+            || (NULL == CU_add_test(pSuite, "SCPI_ErrorQueue", testErrorQueue))
             ) {
         CU_cleanup_registry();
         return CU_get_error();

--
Gitblit v1.9.1