From 3b99af699baba3ddbec2fbe74af6392678fbe31d Mon Sep 17 00:00:00 2001
From: Jan Breuer <jan.breuer@jaybee.cz>
Date: 周二, 10 11月 2015 01:04:30 +0800
Subject: [PATCH] Add array result functions

---
 libscpi/inc/scpi/types.h       |   10 +
 libscpi/src/parser.c           |  249 ++++++++++++++++++++++++++++++++++-
 libscpi/test/test_scpi_utils.c |   19 ++
 libscpi/src/utils_private.h    |   15 +
 libscpi/inc/scpi/parser.h      |   23 +++
 libscpi/src/utils.c            |   47 ++++++
 6 files changed, 350 insertions(+), 13 deletions(-)

diff --git a/libscpi/inc/scpi/parser.h b/libscpi/inc/scpi/parser.h
index b645dfe..4cc088d 100644
--- a/libscpi/inc/scpi/parser.h
+++ b/libscpi/inc/scpi/parser.h
@@ -50,16 +50,37 @@
 
     size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len);
 #define SCPI_ResultMnemonic(context, data) SCPI_ResultCharacters((context), (data), strlen(data))
+#define SCPI_ResultUInt8Base SCPI_ResultUInt32Base
+#define SCPI_ResultUInt8(c, v) SCPI_ResultUInt32Base((c), (v), 10)
+#define SCPI_ResultInt8 SCPI_ResultInt32
+#define SCPI_ResultUInt16Base SCPI_ResultUInt32Base
+#define SCPI_ResultUInt16(c, v) SCPI_ResultUInt32Base((c), (v), 10)
+#define SCPI_ResultInt16 SCPI_ResultInt32
     size_t SCPI_ResultUInt32Base(scpi_t * context, uint32_t val, int8_t base);
+#define SCPI_ResultUInt32(c, v) SCPI_ResultUInt32Base((c), (v), 10)
     size_t SCPI_ResultInt32(scpi_t * context, int32_t val);
     size_t SCPI_ResultUInt64Base(scpi_t * context, uint64_t val, int8_t base);
+#define SCPI_ResultUInt64(c, v) SCPI_ResultUInt64Base((c), (v), 10)
     size_t SCPI_ResultInt64(scpi_t * context, int64_t val);
     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_ResultArbitraryBlock(scpi_t * context, const char * data, size_t len);
+    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);
     size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val);
 
+    size_t SCPI_ResultArrayInt8(scpi_t * context, const int8_t * array, size_t count, scpi_array_format_t format);
+    size_t SCPI_ResultArrayUInt8(scpi_t * context, const uint8_t * array, size_t count, scpi_array_format_t format);
+    size_t SCPI_ResultArrayInt16(scpi_t * context, const int16_t * array, size_t count, scpi_array_format_t format);
+    size_t SCPI_ResultArrayUInt16(scpi_t * context, const uint16_t * array, size_t count, scpi_array_format_t format);
+    size_t SCPI_ResultArrayInt32(scpi_t * context, const int32_t * array, size_t count, scpi_array_format_t format);
+    size_t SCPI_ResultArrayUInt32(scpi_t * context, const uint32_t * array, size_t count, scpi_array_format_t format);
+    size_t SCPI_ResultArrayInt64(scpi_t * context, const int64_t * array, size_t count, scpi_array_format_t format);
+    size_t SCPI_ResultArrayUInt64(scpi_t * context, const uint64_t * array, size_t count, scpi_array_format_t format);
+    size_t SCPI_ResultArrayFloat(scpi_t * context, const float * array, size_t count, scpi_array_format_t format);
+    size_t SCPI_ResultArrayDouble(scpi_t * context, const double * array, size_t count, scpi_array_format_t format);
+
     scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory);
     scpi_bool_t SCPI_ParamIsValid(scpi_parameter_t * parameter);
     scpi_bool_t SCPI_ParamErrorOccurred(scpi_t * context);
diff --git a/libscpi/inc/scpi/types.h b/libscpi/inc/scpi/types.h
index 38ee018..4d56a82 100644
--- a/libscpi/inc/scpi/types.h
+++ b/libscpi/inc/scpi/types.h
@@ -303,8 +303,18 @@
         void * user_context;
         scpi_parser_state_t parser_state;
         const char * idn[4];
+        size_t arbitrary_reminding;
     };
 
+    enum _scpi_array_format_t {
+        SCPI_FORMAT_ASCII = 0,
+        SCPI_FORMAT_NORMAL = 1,
+        SCPI_FORMAT_SWAPPED = 2,
+        SCPI_FORMAT_BIGENDIAN = SCPI_FORMAT_NORMAL,
+        SCPI_FORMAT_LITTLEENDIAN = SCPI_FORMAT_SWAPPED,
+    };
+    typedef enum _scpi_array_format_t scpi_array_format_t;
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/libscpi/src/parser.c b/libscpi/src/parser.c
index 62dc151..faaeb3f 100644
--- a/libscpi/src/parser.c
+++ b/libscpi/src/parser.c
@@ -129,6 +129,7 @@
     context->cmd_error = FALSE;
     context->output_count = 0;
     context->input_count = 0;
+    context->arbitrary_reminding = 0;
 
     /* if callback exists - call command callback */
     if (cmd->callback != NULL) {
@@ -486,14 +487,12 @@
 }
 
 /**
- * Write arbitrary block program data to the result
+ * Write arbitrary block header with length
  * @param context
- * @param data
  * @param len
  * @return
  */
-size_t SCPI_ResultArbitraryBlock(scpi_t * context, const char * data, size_t len) {
-    size_t result = 0;
+size_t SCPI_ResultArbitraryBlockHeader(scpi_t * context, size_t len) {
     char block_header[12];
     size_t header_len;
     block_header[0] = '#';
@@ -502,10 +501,44 @@
     header_len = strlen(block_header + 2);
     block_header[1] = (char) (header_len + '0');
 
-    result += writeData(context, block_header, header_len + 2);
-    result += writeData(context, data, len);
+    context->arbitrary_reminding = len;
+    return writeData(context, block_header, header_len + 2);
+}
 
-    context->output_count++;
+/**
+ * Add data to arbitrary block
+ * @param context
+ * @param data
+ * @param len
+ * @return
+ */
+size_t SCPI_ResultArbitraryBlockData(scpi_t * context, const void * data, size_t len) {
+
+    if (context->arbitrary_reminding < len) {
+        SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+        return 0;
+    }
+
+    context->arbitrary_reminding -= len;
+
+    if (context->arbitrary_reminding == 0) {
+        context->output_count++;
+    }
+
+    return writeData(context, (const char *) data, len);
+}
+
+/**
+ * Write arbitrary block program data to the result
+ * @param context
+ * @param data
+ * @param len
+ * @return
+ */
+size_t SCPI_ResultArbitraryBlock(scpi_t * context, const void * data, size_t len) {
+    size_t result = 0;
+    result += SCPI_ResultArbitraryBlockHeader(context, len);
+    result += SCPI_ResultArbitraryBlockData(context, data, len);
     return result;
 }
 
@@ -1351,6 +1384,7 @@
 }
 
 #if USE_COMMAND_TAGS
+
 /**
  * Return the .tag field of the matching scpi_command_t
  * @param context
@@ -1391,3 +1425,204 @@
 scpi_bool_t SCPI_ParamErrorOccurred(scpi_t * context) {
     return context->cmd_error;
 }
+
+/**
+ * Result binary array and swap bytes if needed (native endiannes != required endiannes)
+ * @param context
+ * @param array
+ * @param count
+ * @param item_size
+ * @param format
+ * @return 
+ */
+static size_t parserResultArrayBinary(scpi_t * context, const void * array, size_t count, size_t item_size, scpi_array_format_t format) {
+
+    if (SCPI_GetNativeFormat() == format) {
+        switch (item_size) {
+            case 1:
+            case 2:
+            case 4:
+            case 8:
+                return SCPI_ResultArbitraryBlock(context, array, count * item_size);
+            default:
+                SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+                return 0;
+        }
+    } else {
+        size_t result = 0;
+        size_t i;
+        switch (item_size) {
+            case 1:
+            case 2:
+            case 4:
+            case 8:
+                result += SCPI_ResultArbitraryBlockHeader(context, count * item_size);
+            default:
+                SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR);
+                return 0;
+        }
+
+        switch (item_size) {
+            case 1:
+                result += SCPI_ResultArbitraryBlockData(context, array, count);
+                break;
+            case 2:
+                for (i = 0; i < count; i++) {
+                    uint16_t val = SCPI_Swap16(((uint16_t*)array)[i]);
+                    result += SCPI_ResultArbitraryBlockData(context, &val, item_size);
+                }
+                break;
+            case 4:
+                for (i = 0; i < count; i++) {
+                    uint32_t val = SCPI_Swap32(((uint32_t*)array)[i]);
+                    result += SCPI_ResultArbitraryBlockData(context, &val, item_size);
+                }
+                break;
+            case 8:
+                for (i = 0; i < count; i++) {
+                    uint64_t val = SCPI_Swap64(((uint64_t*)array)[i]);
+                    result += SCPI_ResultArbitraryBlockData(context, &val, item_size);
+                }
+                break;
+        }
+
+        return result;
+    }
+}
+
+
+#define RESULT_ARRAY(func) do {\
+    size_t result;\
+    if (format == SCPI_FORMAT_ASCII) {\
+        size_t i;\
+        for (i = 0; i < count; i++) {\
+            result += func(context, array[i]);\
+        }\
+        if (count > 0) {\
+            result += count - 1; /* add length of commas */\
+        }\
+    } else {\
+        result = parserResultArrayBinary(context, array, count, sizeof(*array), format);\
+    }\
+    return result;\
+} while(0)
+
+/**
+ * Result array of signed 8bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayInt8(scpi_t * context, const int8_t * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultInt8);
+}
+
+/**
+ * Result array of unsigned 8bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return
+ */
+size_t SCPI_ResultArrayUInt8(scpi_t * context, const uint8_t * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultUInt8);
+}
+
+/**
+ * Result array of signed 16bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return 
+ */
+size_t SCPI_ResultArrayInt16(scpi_t * context, const int16_t * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultInt16);
+}
+
+/**
+ * Result array of unsigned 16bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return 
+ */
+size_t SCPI_ResultArrayUInt16(scpi_t * context, const uint16_t * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultUInt16);
+}
+
+/**
+ * Result array of signed 32bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return 
+ */
+size_t SCPI_ResultArrayInt32(scpi_t * context, const int32_t * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultInt32);
+}
+
+/**
+ * Result array of unsigned 32bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return 
+ */
+size_t SCPI_ResultArrayUInt32(scpi_t * context, const uint32_t * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultUInt32);
+}
+
+/**
+ * Result array of signed 64bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return 
+ */
+size_t SCPI_ResultArrayInt64(scpi_t * context, const int64_t * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultInt64);
+}
+
+/**
+ * Result array of unsigned 64bit integers
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return 
+ */
+size_t SCPI_ResultArrayUInt64(scpi_t * context, const uint64_t * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultUInt64);
+}
+
+/**
+ * Result array of floats
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return 
+ */
+size_t SCPI_ResultArrayFloat(scpi_t * context, const float * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultFloat);
+}
+
+/**
+ * Result array of doubles
+ * @param context
+ * @param array
+ * @param count
+ * @param format
+ * @return 
+ */
+size_t SCPI_ResultArrayDouble(scpi_t * context, const double * array, size_t count, scpi_array_format_t format) {
+    RESULT_ARRAY(SCPI_ResultDouble);
+}
diff --git a/libscpi/src/utils.c b/libscpi/src/utils.c
index f69428d..7902569 100644
--- a/libscpi/src/utils.c
+++ b/libscpi/src/utils.c
@@ -928,3 +928,50 @@
     strncpy(__s, buffer, __ssize);
     return __s;
 }
+
+/**
+ * Get native CPU endiannes
+ * @return 
+ */
+scpi_array_format_t SCPI_GetNativeFormat(void) {
+    // @todo: endianity runtime test
+    return SCPI_FORMAT_LITTLEENDIAN;
+}
+
+/**
+ * Swap 16bit number
+ * @param val
+ * @return 
+ */
+uint16_t SCPI_Swap16(uint16_t val) {
+    return ((val & 0x00FF) << 8) | 
+            ((val & 0xFF00) >> 8);
+}
+
+/**
+ * Swap 32bit number
+ * @param val
+ * @return 
+ */
+uint32_t SCPI_Swap32(uint32_t val) {
+    return ((val & 0x000000FF) << 24) |
+            ((val & 0x0000FF00) << 8) |
+            ((val & 0x00FF0000) >> 8) |
+            ((val & 0xFF000000) >> 24);
+}
+
+/**
+ * Swap 64bit number
+ * @param val
+ * @return 
+ */
+uint64_t SCPI_Swap64(uint64_t val) {
+    return ((val & 0x00000000000000FFul) << 56) |
+            ((val & 0x000000000000FF00ul) << 40) |
+            ((val & 0x0000000000FF0000ul) << 24) |
+            ((val & 0x00000000FF000000ul) << 8) |
+            ((val & 0x000000FF00000000ul) >> 8) |
+            ((val & 0x0000FF0000000000ul) >> 24) |
+            ((val & 0x00FF000000000000ul) >> 40) |
+            ((val & 0xFF00000000000000ul) >> 56);
+}
\ No newline at end of file
diff --git a/libscpi/src/utils_private.h b/libscpi/src/utils_private.h
index b96d73d..671dea0 100644
--- a/libscpi/src/utils_private.h
+++ b/libscpi/src/utils_private.h
@@ -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_utils.h
  * @date   Thu Nov 15 10:58:45 UTC 2012
- * 
+ *
  * @brief  Conversion routines and string manipulation routines
- * 
- * 
+ *
+ *
  */
 
 #ifndef SCPI_UTILS_PRIVATE_H
@@ -74,6 +74,11 @@
 #define SCPI_DTOSTRE_PLUS_SIGN   4
     char * SCPI_dtostre(double __val, char * __s, size_t __ssize, unsigned char __prec, unsigned char __flags);
 
+    scpi_array_format_t SCPI_GetNativeFormat(void);
+    uint16_t SCPI_Swap16(uint16_t val);
+    uint32_t SCPI_Swap32(uint32_t val);
+    uint64_t SCPI_Swap64(uint64_t val);
+
 #if !HAVE_STRNLEN
     size_t BSD_strnlen(const char *s, size_t maxlen) LOCAL;
 #endif
diff --git a/libscpi/test/test_scpi_utils.c b/libscpi/test/test_scpi_utils.c
index f13f63b..98a7305 100644
--- a/libscpi/test/test_scpi_utils.c
+++ b/libscpi/test/test_scpi_utils.c
@@ -726,6 +726,24 @@
     TEST_COMPOSE_COMMAND(":A;C", 2, 3, 1, ":C", TRUE);
 }
 
+static void test_swap(void) {
+#define TEST_SWAP(l, a, b) CU_ASSERT_EQUAL(SCPI_Swap##l(a), b)
+
+    TEST_SWAP(16, 0x0011, 0x1100);
+    TEST_SWAP(16, 0x1234, 0x3412);
+
+    TEST_SWAP(32, 0x00000011, 0x11000000);
+    TEST_SWAP(32, 0x00001234, 0x34120000);
+    TEST_SWAP(32, 0x00AB1234, 0x3412AB00);
+    TEST_SWAP(32, 0xCDAB1234, 0x3412ABCD);
+
+    TEST_SWAP(64, 0x0000000000000011ull, 0x1100000000000000ull);
+    TEST_SWAP(64, 0x0000000000001234ull, 0x3412000000000000ull);
+    TEST_SWAP(64, 0x0000000000AB1234ull, 0x3412AB0000000000ull);
+    TEST_SWAP(64, 0x00000000CDAB1234ull, 0x3412ABCD00000000ull);
+    TEST_SWAP(64, 0x123456789ABCDEF0ull, 0xF0DEBC9A78563412ull);
+}
+
 int main() {
     unsigned int result;
     CU_pSuite pSuite = NULL;
@@ -761,6 +779,7 @@
             || (NULL == CU_add_test(pSuite, "matchPattern", test_matchPattern))
             || (NULL == CU_add_test(pSuite, "matchCommand", test_matchCommand))
             || (NULL == CU_add_test(pSuite, "composeCompoundCommand", test_composeCompoundCommand))
+            || (NULL == CU_add_test(pSuite, "swap", test_swap))
             ) {
         CU_cleanup_registry();
         return CU_get_error();

--
Gitblit v1.9.1