Nigel Rantor / azure_c_shared_utility

Fork of azure_c_shared_utility by Azure IoT

Files at this revision

API Documentation at this revision

Comitter:
Azure.IoT.Build
Date:
Wed Dec 14 16:00:59 2016 -0800
Parent:
15:956c6d205aa7
Child:
17:9051ba70fc73
Commit message:
1.1.2

Changed in this revision

azure_c_shared_utility/connection_string_parser.h Show annotated file Show diff for this revision Revisions of this file
azure_c_shared_utility/tickcounter.h Show annotated file Show diff for this revision Revisions of this file
azure_c_shared_utility/xlogging.h Show annotated file Show diff for this revision Revisions of this file
connection_string_parser.c Show annotated file Show diff for this revision Revisions of this file
strings.c Show annotated file Show diff for this revision Revisions of this file
tickcounter_mbed.cpp Show annotated file Show diff for this revision Revisions of this file
xlogging.c Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/azure_c_shared_utility/connection_string_parser.h	Wed Dec 14 16:00:59 2016 -0800
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#ifndef CONNECTION_STRING_PARSER_H
+#define CONNECTION_STRING_PARSER_H
+
+#include "azure_c_shared_utility/umock_c_prod.h"
+#include "azure_c_shared_utility/map.h" 
+#include "azure_c_shared_utility/strings.h"
+
+#ifdef __cplusplus
+extern "C" 
+{
+#endif
+
+    MOCKABLE_FUNCTION(, MAP_HANDLE, connectionstringparser_parse, STRING_HANDLE, connection_string);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONNECTION_STRING_PARSER_H */
--- a/azure_c_shared_utility/tickcounter.h	Wed Nov 16 21:38:39 2016 -0800
+++ b/azure_c_shared_utility/tickcounter.h	Wed Dec 14 16:00:59 2016 -0800
@@ -13,11 +13,12 @@
 
 #include "azure_c_shared_utility/umock_c_prod.h"
 
-	typedef struct TICK_COUNTER_INSTANCE_TAG* TICK_COUNTER_HANDLE;
+    typedef uint_fast32_t tickcounter_ms_t;
+    typedef struct TICK_COUNTER_INSTANCE_TAG* TICK_COUNTER_HANDLE;
 
     MOCKABLE_FUNCTION(, TICK_COUNTER_HANDLE, tickcounter_create);
     MOCKABLE_FUNCTION(, void, tickcounter_destroy, TICK_COUNTER_HANDLE, tick_counter);
-    MOCKABLE_FUNCTION(, int, tickcounter_get_current_ms, TICK_COUNTER_HANDLE, tick_counter, uint64_t*, current_ms);
+    MOCKABLE_FUNCTION(, int, tickcounter_get_current_ms, TICK_COUNTER_HANDLE, tick_counter, tickcounter_ms_t*, current_ms);
 
 #ifdef __cplusplus
 }
--- a/azure_c_shared_utility/xlogging.h	Wed Nov 16 21:38:39 2016 -0800
+++ b/azure_c_shared_utility/xlogging.h	Wed Dec 14 16:00:59 2016 -0800
@@ -55,6 +55,12 @@
 so we compacted the log in the macro LogInfo.
 */
 #include "esp8266/azcpgmspace.h"
+#define LOG(log_category, log_options, FORMAT, ...) { \
+        const char* __localFORMAT = PSTR(FORMAT); \
+        os_printf(__localFORMAT, ##__VA_ARGS__); \
+        os_printf("\r\n"); \
+}
+
 #define LogInfo(FORMAT, ...) { \
         const char* __localFORMAT = PSTR(FORMAT); \
         os_printf(__localFORMAT, ##__VA_ARGS__); \
@@ -127,4 +133,27 @@
 
 #endif /* ARDUINO_ARCH_ESP8266 */
 
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+    /**
+     * @brief   Print the memory content byte pre byte in hexadecimal and as a char it the byte correspond to any printable ASCII chars.
+     *
+     *    This function prints the ‘size’ bytes in the ‘buf’ to the log. It will print in portions of 16 bytes, 
+     *         and will print the byte as a hexadecimal value, and, it is a printable, this function will print 
+     *         the correspondent ASCII character.
+     *    Non printable characters will shows as a single ‘.’. 
+     *    For this function, printable characters are all characters between ‘ ‘ (0x20) and ‘~’ (0x7E).
+     *
+     * @param   buf  Pointer to the memory address with the buffer to print.
+     * @param   size Number of bytes to print.
+     */
+    extern void xlogging_dump_buffer(const void* buf, size_t size);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
 #endif /* XLOGGING_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/connection_string_parser.c	Wed Dec 14 16:00:59 2016 -0800
@@ -0,0 +1,133 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+#include "azure_c_shared_utility/connection_string_parser.h"
+#include "azure_c_shared_utility/map.h"
+#include "azure_c_shared_utility/strings.h"
+#include "azure_c_shared_utility/string_tokenizer.h"
+#include <stdbool.h>
+#include "azure_c_shared_utility/xlogging.h"
+
+/* Codes_SRS_CONNECTIONSTRINGPARSER_01_001: [connectionstringparser_parse shall parse all key value pairs from the connection_string passed in as argument and return a new map that holds the key/value pairs.] */
+MAP_HANDLE connectionstringparser_parse(STRING_HANDLE connection_string)
+{
+    MAP_HANDLE result;
+
+    if (connection_string == NULL)
+    {
+        /* Codes_SRS_CONNECTIONSTRINGPARSER_01_002: [If connection_string is NULL then connectionstringparser_parse shall fail and return NULL.] */
+        result = NULL;
+        LogError("NULL connection string passed to tokenizer.\r\n");
+    }
+    else
+    {
+        /* Codes_SRS_CONNECTIONSTRINGPARSER_01_003: [connectionstringparser_parse shall create a STRING tokenizer to be used for parsing the connection string, by calling STRING_TOKENIZER_create.] */
+        /* Codes_SRS_CONNECTIONSTRINGPARSER_01_004: [connectionstringparser_parse shall start scanning at the beginning of the connection string.] */
+        STRING_TOKENIZER_HANDLE tokenizer = STRING_TOKENIZER_create(connection_string);
+        if (tokenizer == NULL)
+        {
+            /* Codes_SRS_CONNECTIONSTRINGPARSER_01_015: [If STRING_TOKENIZER_create fails, connectionstringparser_parse shall fail and return NULL.] */
+            result = NULL;
+            LogError("Error creating STRING tokenizer.\r\n");
+        }
+        else
+        {
+            /* Codes_SRS_CONNECTIONSTRINGPARSER_01_016: [2 STRINGs shall be allocated in order to hold the to be parsed key and value tokens.] */
+            STRING_HANDLE token_key_string = STRING_new();
+            if (token_key_string == NULL)
+            {
+                /* Codes_SRS_CONNECTIONSTRINGPARSER_01_017: [If allocating the STRINGs fails connectionstringparser_parse shall fail and return NULL.] */
+                result = NULL;
+                LogError("Error creating key token STRING.\r\n");
+            }
+            else
+            {
+                STRING_HANDLE token_value_string = STRING_new();
+                if (token_value_string == NULL)
+                {
+                    /* Codes_SRS_CONNECTIONSTRINGPARSER_01_017: [If allocating the STRINGs fails connectionstringparser_parse shall fail and return NULL.] */
+                    result = NULL;
+                    LogError("Error creating value token STRING.\r\n");
+                }
+                else
+                {
+                    result = Map_Create(NULL);
+                    if (result == NULL)
+                    {
+                        /* Codes_SRS_CONNECTIONSTRINGPARSER_01_018: [If creating the result map fails, then connectionstringparser_parse shall return NULL.] */
+                        LogError("Error creating Map\r\n");
+                    }
+                    else
+                    {
+                        /* Codes_SRS_CONNECTIONSTRINGPARSER_01_005: [The following actions shall be repeated until parsing is complete:] */
+                        /* Codes_SRS_CONNECTIONSTRINGPARSER_01_006: [connectionstringparser_parse shall find a token (the key of the key/value pair) delimited by the `=` character, by calling STRING_TOKENIZER_get_next_token.] */
+                        /* Codes_SRS_CONNECTIONSTRINGPARSER_01_007: [If STRING_TOKENIZER_get_next_token fails, parsing shall be considered complete.] */
+                        while (STRING_TOKENIZER_get_next_token(tokenizer, token_key_string, "=") == 0)
+                        {
+                            bool is_error = false;
+
+                            /* Codes_SRS_CONNECTIONSTRINGPARSER_01_008: [connectionstringparser_parse shall find a token (the value of the key/value pair) delimited by the `;` character, by calling STRING_TOKENIZER_get_next_token.] */
+                            if (STRING_TOKENIZER_get_next_token(tokenizer, token_value_string, ";") != 0)
+                            {
+                                /* Codes_SRS_CONNECTIONSTRINGPARSER_01_009: [If STRING_TOKENIZER_get_next_token fails, connectionstringparser_parse shall fail and return NULL (freeing the allocated result map).] */
+                                is_error = true;
+                                LogError("Error reading value token from the connection string.\r\n");
+                            }
+                            else
+                            {
+                                /* Codes_SRS_CONNECTIONSTRINGPARSER_01_011: [The C strings for the key and value shall be extracted from the previously parsed STRINGs by using STRING_c_str.] */
+                                const char* token = STRING_c_str(token_key_string);
+                                /* Codes_SRS_CONNECTIONSTRINGPARSER_01_013: [If STRING_c_str fails then connectionstringparser_parse shall fail and return NULL (freeing the allocated result map).] */
+                                if ((token == NULL) ||
+                                    /* Codes_SRS_CONNECTIONSTRINGPARSER_01_019: [If the key length is zero then connectionstringparser_parse shall fail and return NULL (freeing the allocated result map).] */
+                                    (strlen(token) == 0))
+                                {
+                                    is_error = true;
+                                    LogError("The key token is NULL or empty.\r\n");
+                                }
+                                else
+                                {
+                                    /* Codes_SRS_CONNECTIONSTRINGPARSER_01_011: [The C strings for the key and value shall be extracted from the previously parsed STRINGs by using STRING_c_str.] */
+                                    const char* value = STRING_c_str(token_value_string);
+                                    if (value == NULL)
+                                    {
+                                        /* Codes_SRS_CONNECTIONSTRINGPARSER_01_013: [If STRING_c_str fails then connectionstringparser_parse shall fail and return NULL (freeing the allocated result map).] */
+                                        is_error = true;
+                                        LogError("Could not get C string for value token.\r\n");
+                                    }
+                                    else
+                                    {
+                                        /* Codes_SRS_CONNECTIONSTRINGPARSER_01_010: [The key and value shall be added to the result map by using Map_Add.] */
+                                        if (Map_Add(result, token, value) != 0)
+                                        {
+                                            /* Codes_SRS_CONNECTIONSTRINGPARSER_01_012: [If Map_Add fails connectionstringparser_parse shall fail and return NULL (freeing the allocated result map).] */
+                                            is_error = true;
+                                            LogError("Could not add the key/value pair to the result map.\r\n");
+                                        }
+                                    }
+                                }
+                            }
+
+                            if (is_error)
+                            {
+                                LogError("Error parsing connection string.\r\n");
+                                Map_Destroy(result);
+                                result = NULL;
+                                break;
+                            }
+                        }
+                    }
+
+                    STRING_delete(token_value_string);
+                }
+
+                STRING_delete(token_key_string);
+            }
+
+            /* Codes_SRS_CONNECTIONSTRINGPARSER_01_014: [After the parsing is complete the previously allocated STRINGs and STRING tokenizer shall be freed by calling STRING_TOKENIZER_destroy.] */
+            STRING_TOKENIZER_destroy(tokenizer);
+        }
+    }
+
+    return result;
+}
--- a/strings.c	Wed Nov 16 21:38:39 2016 -0800
+++ b/strings.c	Wed Dec 14 16:00:59 2016 -0800
@@ -125,6 +125,15 @@
 STRING_HANDLE STRING_construct_sprintf(const char* format, ...)
 {
     STRING* result;
+    
+#ifdef ARDUINO_ARCH_ESP8266
+    size_t maxBufSize = 512;
+    char buf[512];
+#else
+    size_t maxBufSize = 0;
+    char* buf = NULL;
+#endif
+
     if (format != NULL)
     {
         va_list arg_list;
@@ -132,7 +141,7 @@
         va_start(arg_list, format);
 
         /* Codes_SRS_STRING_07_041: [STRING_construct_sprintf shall determine the size of the resulting string and allocate the necessary memory.] */
-        length = vsnprintf(NULL, 0, format, arg_list);
+        length = vsnprintf(buf, maxBufSize, format, arg_list);
         va_end(arg_list);
         if (length > 0)
         {
@@ -504,6 +513,15 @@
 int STRING_sprintf(STRING_HANDLE handle, const char* format, ...)
 {
     int result;
+    
+#ifdef ARDUINO_ARCH_ESP8266
+    size_t maxBufSize = 512;
+    char buf[512];
+#else
+    size_t maxBufSize = 0;
+    char* buf = NULL;
+#endif
+    
     if (handle == NULL || format == NULL)
     {
         /* Codes_SRS_STRING_07_042: [if the parameters s1 or format are NULL then STRING_sprintf shall return non zero value.] */
@@ -516,7 +534,7 @@
 		int s2Length;
         va_start(arg_list, format);
 
-        s2Length = vsnprintf(NULL, 0, format, arg_list);
+        s2Length = vsnprintf(buf, maxBufSize, format, arg_list);
         va_end(arg_list);
         if (s2Length < 0)
         {
--- a/tickcounter_mbed.cpp	Wed Nov 16 21:38:39 2016 -0800
+++ b/tickcounter_mbed.cpp	Wed Dec 14 16:00:59 2016 -0800
@@ -16,7 +16,7 @@
 {
 public:
     clock_t last_clock_value;
-    uint64_t current_ms;
+    tickcounter_ms_t current_ms;
 };
 
 TICK_COUNTER_HANDLE tickcounter_create(void)
@@ -36,7 +36,7 @@
     }
 }
 
-int tickcounter_get_current_ms(TICK_COUNTER_HANDLE tick_counter, uint64_t* current_ms)
+int tickcounter_get_current_ms(TICK_COUNTER_HANDLE tick_counter, tickcounter_ms_t * current_ms)
 {
     int result;
     if (tick_counter == NULL || current_ms == NULL)
--- a/xlogging.c	Wed Nov 16 21:38:39 2016 -0800
+++ b/xlogging.c	Wed Dec 14 16:00:59 2016 -0800
@@ -53,4 +53,68 @@
     return global_log_function;
 }
 
+/* Print up to 16 bytes per line. */
+#define LINE_SIZE 16
+
+/* Return the printable char for the provided value. */
+#define PRINTABLE(c)         ((c >= ' ') && (c <= '~')) ? (char)c : '.'
+
+/* Convert the lower nibble of the provided byte to a hexadecimal printable char. */
+#define HEX_STR(c)           (((c) & 0xF) < 0xA) ? (char)(((c) & 0xF) + '0') : (char)(((c) & 0xF) - 0xA + 'A')
+
+void xlogging_dump_buffer(const void* buf, size_t size)
+{
+    char charBuf[LINE_SIZE + 1];
+    char hexBuf[LINE_SIZE * 3 + 1];
+    char countbuf = 0;
+    const unsigned char* bufAsChar = (const unsigned char*)buf;
+    const unsigned char* startPos = bufAsChar;
+    
+    /* Print the whole buffer. */
+    for (size_t i = 0; i < size; i++)
+    {
+        /* Store the printable value of the char in the charBuf to print. */
+        charBuf[countbuf] = PRINTABLE(*bufAsChar);
+
+        /* Convert the high nibble to a printable hexadecimal value. */
+        hexBuf[countbuf * 3] = HEX_STR(*bufAsChar >> 4);
+
+        /* Convert the low nibble to a printable hexadecimal value. */
+        hexBuf[countbuf * 3 + 1] = HEX_STR(*bufAsChar);
+
+        hexBuf[countbuf * 3 + 2] = ' ';
+
+        countbuf++;
+        bufAsChar++;
+        /* If the line is full, print it to start another one. */
+        if (countbuf == LINE_SIZE)
+        {
+            charBuf[countbuf] = '\0';
+            hexBuf[countbuf * 3] = '\0';
+            LOG(LOG_TRACE, 0, "%p: %s    %s", startPos, hexBuf, charBuf);
+            countbuf = 0;
+            startPos = bufAsChar;
+        }
+    }
+
+    /* If the last line does not fit the line size. */
+    if (countbuf > 0)
+    {
+        /* Close the charBuf string. */
+        charBuf[countbuf] = '\0';
+
+        /* Fill the hexBuf with spaces to keep the charBuf alignment. */
+        while ((countbuf++) < LINE_SIZE - 1)
+        {
+            hexBuf[countbuf * 3] = ' ';
+            hexBuf[countbuf * 3 + 1] = ' ';
+            hexBuf[countbuf * 3 + 2] = ' ';
+        }
+        hexBuf[countbuf * 3] = '\0';
+
+        /* Print the last line. */
+        LOG(LOG_TRACE, 0, "%p: %s    %s", startPos, hexBuf, charBuf);
+    }
+}
+
 #endif