diff --git a/Examples/StreamOverSocket/.gitignore b/Examples/StreamOverSocket/.gitignore
new file mode 100644
index 0000000..2dff2f0
--- /dev/null
+++ b/Examples/StreamOverSocket/.gitignore
@@ -0,0 +1 @@
+cmake-build-debug
diff --git a/Examples/StreamOverSocket/.idea/.gitignore b/Examples/StreamOverSocket/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/Examples/StreamOverSocket/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/Examples/StreamOverSocket/.idea/misc.xml b/Examples/StreamOverSocket/.idea/misc.xml
new file mode 100644
index 0000000..4619d2b
--- /dev/null
+++ b/Examples/StreamOverSocket/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Examples/StreamOverSocket/.idea/modules.xml b/Examples/StreamOverSocket/.idea/modules.xml
new file mode 100644
index 0000000..95a2860
--- /dev/null
+++ b/Examples/StreamOverSocket/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Examples/StreamOverSocket/.idea/serialPort.iml b/Examples/StreamOverSocket/.idea/serialPort.iml
new file mode 100644
index 0000000..f08604b
--- /dev/null
+++ b/Examples/StreamOverSocket/.idea/serialPort.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Examples/StreamOverSocket/.idea/vcs.xml b/Examples/StreamOverSocket/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/Examples/StreamOverSocket/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Examples/StreamOverSocket/CMakeLists.txt b/Examples/StreamOverSocket/CMakeLists.txt
new file mode 100644
index 0000000..0b2a06a
--- /dev/null
+++ b/Examples/StreamOverSocket/CMakeLists.txt
@@ -0,0 +1,25 @@
+cmake_minimum_required(VERSION 3.25)
+project(serialPort C)
+
+set(CMAKE_C_STANDARD 11)
+#set(ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(SOURCES
+ main.c
+ uart_sock.c
+ userCodes.c
+ Str/Str.c
+ Stream/StreamBuffer.c
+ Stream/UARTStream.c
+ Stream/buffer.c
+ Stream/OutputStream.c
+ Stream/InputStream.c
+ arduino/arduino.c
+ )
+
+#target_include_directories(${PROJECT_NAME} PRIVATE ${ROOT_DIR} ${ROOT_DIR}/Stream ${ROOT_DIR}/Str)
+include_directories(parser Str Stream arduino ec200)
+add_executable(serialPort ${SOURCES})
+
+if (WIN32)
+ target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32)
+endif ()
\ No newline at end of file
diff --git a/Examples/StreamOverSocket/README.md b/Examples/StreamOverSocket/README.md
new file mode 100644
index 0000000..7a2a7ca
--- /dev/null
+++ b/Examples/StreamOverSocket/README.md
@@ -0,0 +1 @@
+# StreamOverSocket
diff --git a/Examples/StreamOverSocket/Str/Str.c b/Examples/StreamOverSocket/Str/Str.c
new file mode 100644
index 0000000..ca291c1
--- /dev/null
+++ b/Examples/StreamOverSocket/Str/Str.c
@@ -0,0 +1,2270 @@
+#include "Str.h"
+
+#if STR_USE_STRING_LIBRARY
+ #include
+#endif
+
+/**
+ * variables
+ **/
+
+#if STR_USE_CONST_VARIABLES
+ const Str_Radix __Str_Decimal = Str_Decimal;
+ const char __Str_0 = '0';
+ const char __Str_9 = '9';
+ const char __Str_Zero = 0;
+ const char __Str_One = 1;
+ const char __Str_Null = '\0';
+ const Str_LenType __Str_MaxLength = STR_MAX_LENGTH;
+#else
+ #define __Str_Decimal Str_Decimal
+ #define __Str_MaxLength STR_MAX_LENGTH
+ #define __Str_0 '0'
+ #define __Str_9 '9'
+ #define __Str_Zero 0
+ #define __Str_One 1
+ #define __Str_Null '\0'
+#endif // STR_USE_CONST_VARIABLES
+
+#ifndef NULL
+ #define NULL ((const void*) 0)
+#endif
+
+
+/**
+ * @brief this Function can use for copy array into another array with reverse order
+ *
+ * @param src address of source array that we want copy from
+ * @param dest address of destination array that we want copy into
+ * @param len number of bytes
+ * @return void* address of destination array
+ */
+void* Mem_copyReverse(void* dest, const void* src, Mem_LenType len) {
+ unsigned char* pD = (unsigned char*) dest;
+ unsigned char* pS = (unsigned char*) src + (len - 1);
+ while (len-- > 0){
+ *pD++ = *pS--;
+ }
+ return dest;
+}
+/**
+ * @brief reverse order of bytes in array
+ *
+ * @param arr address of array that we want reverse order
+ * @param len number of byte
+ * @return void* address of array
+ */
+void* Mem_reverse(void* arr, Mem_LenType len) {
+ unsigned char* pStart = (unsigned char*) arr;
+ unsigned char* pEnd = &((unsigned char*)arr)[len - 1];
+ unsigned char temp;
+ len >>= 1;
+ while (len-- > 0){
+ temp = *pEnd;
+ *pEnd-- = *pStart;
+ *pStart++ = temp;
+ }
+ return arr;
+}
+/**
+ * @brief this function return address of last character
+ *
+ * @param str
+ * @return
+ */
+char* Str_indexOfEnd(const char* str) {
+ Str_LenType len = Str_len(str);
+ if (len) {
+ return (char*) &str[len - 1];
+ }
+ else {
+ return NULL;
+ }
+}
+/**
+ * @brief this function return end of string (Null character)
+ *
+ * @param str address of string must include 'null' in end of it
+ * @return char* address of null character
+ */
+char* Str_indexOfNull(const char* str) {
+ Str_LenType len = Str_len(str);
+ if (len) {
+ return (char*) &str[len];
+ }
+ else {
+ return NULL;
+ }
+}
+/**
+ * @brief compare two string and result is opposite of Str_compare
+ *
+ * @param str1 address of string 1
+ * @param str2 address of string 2
+ * @return char result of compare,
+ * str1 > str2 -> result < 0
+ * str1 == str2 -> result == 0
+ * str1 < str2 -> result > 0
+ */
+char Str_compareInverse(const char* str1, const char* str2) {
+ return Str_compare(str2, str1);
+}
+/**
+ * @brief compare word in str, with priority of word and continue until word reach null
+ *
+ * @param str address of base string
+ * @param word address of word that we want compare with str
+ * @return char result of compare,
+ * str > word -> result > 0
+ * str == word -> result == 0
+ * str < word -> result < 0
+ */
+char Str_compareWord(const char* str, const char* word) {
+ char res;
+ while (*word != __Str_Null){
+ res = *str++ - *word++;
+ if (res != 0){
+ break;
+ }
+ }
+ return res;
+}
+/**
+ * @brief find first digit in string and return address of digit
+ *
+ * @param str address of string
+ * @return char* address of digit in str, return null if nothing found
+ */
+char* Str_findDigit(const char* str) {
+ while ((*str < __Str_0 || *str > __Str_9) &&
+ *str != __Str_Null){
+ str++;
+ }
+ return *str == __Str_Null ? NULL : (char*) str;
+}
+/**
+ * @brief find first digit in string and return address of digit, keep search until reach null or reach end charachter
+ *
+ * @param str address of string
+ * @param endChar ending character
+ * @return char* address of digit in str, return null if nothing found
+ */
+char* Str_findDigitUntil(const char* str, char endChar) {
+ while ((*str < __Str_0 || *str > __Str_9) &&
+ *str != __Str_Null &&
+ *str != endChar){
+ str++;
+ }
+ return *str == __Str_Null || *str == endChar ? NULL : (char*) str;
+}
+/**
+ * @brief find first digit in string and return address of digit, keep search until reach null or pass the length limit
+ *
+ * @param str address of string
+ * @param len length of string
+ * @return char* address of digit in str, return null if nothing found
+ */
+char* Str_findDigitFix(const char* str, Str_LenType len) {
+ while ((*str < __Str_0 || *str > __Str_9) &&
+ *str != __Str_Null &&
+ len-- > 0){
+ str++;
+ }
+ return *str == __Str_Null || len == 0 ? NULL : (char*) str;
+}
+/**
+ * @brief find a number and return last digit of it
+ *
+ * @param str address of string
+ * @return char* address of digit in str, return null if nothing found
+ */
+char* Str_findLastDigit(const char* str) {
+ str = Str_findDigit(str);
+ if (str != NULL) {
+ while (*str >= __Str_0 && *str <= __Str_9){
+ str++;
+ }
+ str--;
+ }
+ return (char*) str;
+}
+/**
+ * @brief find a number and return last digit of it with ending charachter condition
+ *
+ * @param str address of string
+ * @param endChar ending charachter
+ * @return char* address of digit in str, return null if nothing found
+ */
+char* Str_findLastDigitUntil(const char* str, char endChar) {
+ str = Str_findDigitUntil(str, endChar);
+ if (str != NULL) {
+ while (*str >= __Str_0 && *str <= __Str_9){
+ str++;
+ }
+ str--;
+ }
+ return (char*) str;
+}
+/**
+ * @brief find a number and return last digit of it with length condition
+ *
+ * @param str address of string
+ * @param len length of string
+ * @return char* address of digit in str, return null if nothing found
+ */
+char* Str_findLastDigitFix(const char* str, Str_LenType len) {
+ str = Str_findDigitFix(str, len);
+ if (str != NULL) {
+ while (*str >= __Str_0 && *str <= __Str_9){
+ str++;
+ }
+ str--;
+ }
+ return (char*) str;
+}
+/**
+ * @brief find digit from end of string in backward
+ *
+ * @param str address of string, must include null
+ * @return char* address of digit in str, return null if nothing found
+ */
+char* Str_findReverseDigit(const char* str) {
+ return Str_findReverseDigitFix(str, Str_len(str));
+}
+/**
+ * @brief find digit from end of string in backward with fixed string length
+ *
+ * @param str address of string
+ * @param len lenght of string
+ * @return char* address of digit in str, return null if nothing found
+ */
+char* Str_findReverseDigitFix(const char* str, Str_LenType len) {
+ str = &str[len - 1];
+ while ((*str < __Str_0 || *str > __Str_9) &&
+ len-- > 0){
+ str--;
+ }
+ return *str == __Str_Null || len == 0 ? NULL : (char*) str;
+}
+/**
+ * @brief find multiple indexes of 'c' in string
+ *
+ * @param str address of strings
+ * @param c charachter that we want search for indexes
+ * @param indexes a pointer array that will hold our indexes
+ * @return Str_LenType number of indexes that found
+ */
+Str_LenType Str_indexesOf(const char* str, char c, char const** indexes) {
+ Str_LenType count = 0;
+ while (*str != __Str_Null){
+ if (c == *str){
+ *indexes++ = str;
+ count++;
+ }
+ str++;
+ }
+ return count;
+}
+/**
+ * @brief find multiple indexes of 'c' in string until reach null or pass the limit
+ *
+ * @param str address of strings
+ * @param c charachter that we want search for indexes
+ * @param indexes a pointer array that will hold our indexes
+ * @param len lenght of string
+ * @return Str_LenType number of indexes that found
+ */
+Str_LenType Str_indexesOfFix(const char* str, char c, char const** indexes, Str_LenType len) {
+ Str_LenType count = 0;
+ while (*str != __Str_Null && len-- > 0){
+ if (c == *str){
+ *indexes++ = str;
+ count++;
+ }
+ str++;
+ }
+ return count;
+}
+/**
+ * @brief find multiple indexes of 'c' in string until reach null or ending charachter
+ *
+ * @param str address of strings
+ * @param c charachter that we want search for indexes
+ * @param indexes a pointer array that will hold our indexes
+ * @param endChar ending charachter
+ * @return Str_LenType number of indexes that found
+ */
+Str_LenType Str_indexesOfUntil(const char* str, char c, char const** indexes, char endChar) {
+ Str_LenType count = 0;
+ while (*str != __Str_Null && *str != endChar){
+ if (c == *str){
+ *indexes++ = str;
+ count++;
+ }
+ str++;
+ }
+ return count;
+}
+/**
+ * @brief This Fntion finds the address of a character in a given number and returns the last one
+ *
+ * @param str address of string
+ * @param c charachter that we want to search
+ * @param num The number of times the Fuction looks for a character, must greater than 0
+ * @return char* address of charachter, return null if not found
+ */
+char* Str_indexOfAt(const char* str, char c, Str_LenType num) {
+ if (str != NULL) {
+ if (num > 0) {
+ while ((str = Str_indexOf(str, c)) != NULL && --num > 0) {
+ str = str + 1;
+ }
+ }
+ return (char*) str;
+ }
+ else {
+ return NULL;
+ }
+}
+/**
+ * @brief This Fntion finds the address of a character in a given number and returns the last one until reach null or ending charachter
+ *
+ * @param str address of string
+ * @param c charachter that we want to search
+ * @param num The number of times the Fntion looks for a character
+ * @param end ending charachter
+ * @return char* address of charachter, return null if not found
+ */
+char* Str_indexOfAtUntil(const char* str, char c, Str_LenType num, char end) {
+ return Str_indexOfAtFix(str, c, num, Str_posOf(str, end));
+}
+/**
+ * @brief This Fntion finds the address of a character in a given number and returns the last one until reach null or pass the limit
+ *
+ * @param str address of string
+ * @param c charachter that we want to search
+ * @param num The number of times the Fntion looks for a character
+ * @param len length of string
+ * @return char* address of charachter, return null if not found
+ */
+char* Str_indexOfAtFix(const char* str, char c, Str_LenType num, Str_LenType len) {
+ char* temp = NULL;
+ while (num-- > 0) {
+ temp = Mem_indexOf(str, c, len);
+ if (!temp) {
+ break;
+ }
+ len -= temp - str;
+ str = temp;
+ }
+ return temp;
+}
+
+char* Str_reverseIndexOf(const char* str, char c, const char* startOfStr) {
+ while (startOfStr <= str) {
+ if (*str == c) {
+ return (char*) str;
+ }
+ str--;
+ }
+ return NULL;
+}
+
+char* Str_reverseIndexOfFix(const char* str, char c, int length) {
+ while (length-- > 0) {
+ if (*str == c) {
+ return (char*) str;
+ }
+ str--;
+ }
+ return NULL;
+}
+
+/**
+ * @brief revesre order of charachter in string
+ *
+ * @param str address of string
+ * @return char* address of str
+ */
+char* Str_reverse(char* str) {
+ return Mem_reverse(str, Str_len(str));
+}
+/**
+ * @brief copy source string in reverse order into destination string
+ *
+ * @param src address of source string
+ * @param dest address of destination string
+ * @return char* address of dest
+ */
+char* Str_copyReverse(char* dest, const char* src) {
+ Mem_LenType len = Str_len(src);
+ Mem_copyReverse(dest, src, len);
+ dest[len] = __Str_Null;
+ return dest;
+}
+/**
+ * @brief copy a string into dest from given start position
+ *
+ * @param str address of base string
+ * @param dest address of destination string
+ * @param start Copy start location
+ * @return char* address of dest
+ */
+char* Str_substr(char* dest, const char* str, Str_LenType start) {
+ return Str_copy(dest, &str[start]);
+}
+/**
+ * @brief copy a string into dest from given start position
+ *
+ * @param str address of base string
+ * @param dest address of destination string
+ * @param start Copy start location
+ * @param len length of characters to be copy
+ * @return char* address of dest
+ */
+char* Str_substrFix(char* dest, const char* str, Str_LenType start, Str_LenType len) {
+ Str_copyFix(dest, &str[start], len);
+ dest[len] = __Str_Null;
+ return dest;
+}
+/**
+ * @brief copy a string into dest from given start position until reach ending charachter
+ *
+ * @param str address of base string
+ * @param dest address of destination string
+ * @param start Copy start location
+ * @param endChar ending charachter
+ * @return char* address of dest
+ */
+char* Str_substrUntil(char* dest, const char* str, Str_LenType start, char endChar) {
+ Str_LenType len = Str_posOf(str, endChar);
+ Str_copyFix(dest, &str[start], len);
+ dest[len] = __Str_Null;
+ return dest;
+}
+/**
+ * @brief replace first word that find in string with a another word
+ *
+ * @param str address of string
+ * @param word addres of word
+ * @param replacement address of replacement
+ * @return char* return address of str if word found otherwise return null
+ */
+char* Str_replace(char* str, const char* word, const char* replacement) {
+ char* pWord = Str_indexOfStr(str, word);
+ if (pWord != NULL) {
+ Str_LenType wordLen = Str_len(word);
+ Str_LenType repLen = Str_len(replacement);
+ if (wordLen != repLen) {
+ char* pEndOfWord = pWord + wordLen;
+ int len = (Str_LenType) ((char*) Mem_indexOf(pEndOfWord, __Str_Null, __Str_MaxLength) - pEndOfWord) + 1;
+ Mem_move(pEndOfWord + (repLen - wordLen), pEndOfWord, len);
+ }
+ Str_copyFix(pWord, replacement, repLen);
+ return pWord;
+ }
+ return NULL;
+}
+/**
+ * @brief replace all words that find in string with a replacement word
+ *
+ * @param str address of string
+ * @param word addres of word
+ * @param replacement address of replacement
+ * @return char* return address of str if word found otherwise return null
+ */
+int Str_replaceAll(char* str, const char* word, const char* replacement) {
+ int count = 0;
+ int replacementLen = Str_len(replacement);
+ while ((str = Str_replace(str, word, replacement)) != NULL) {
+ str = str + replacementLen;
+ count++;
+ }
+ return count;
+}
+/**
+ * @brief copy sourc string into destination string until reach ending char
+ *
+ * @param src address of source string
+ * @param dest address of destination string
+ * @param endChar ending character
+ * @return char* return null if source not contain ending character otherwise return destination
+ */
+char* Str_copyUntil(char* dest, const char* src, char endChar) {
+ char* pStr = Str_indexOf(src, endChar);
+ if (pStr != NULL){
+ Str_LenType len = (Str_LenType) (pStr - src);
+ Str_copyFix(dest, src, len);
+ dest[len] = __Str_Null;
+ return dest;
+ }
+ return pStr;
+}
+/**
+ * @brief read a line form source and copy it into destination
+ *
+ * @param src address of source string
+ * @param dest address of destination string
+ * @return char* return null if source not contain ending character otherwise return destination
+ */
+char* Str_copyLine(char* dest, const char* src) {
+ return Str_copyUntil(dest, src, '\n');
+}
+/**
+ * @brief sort array of strings with selection sort algorithm
+ *
+ * @param strs array of strings
+ * @param len length of array
+ * @return char** return address of strs
+ */
+const char** Str_sort(const char** strs, Str_LenType len) {
+ return Str_selectionSortBlock(strs, (Mem_LenType) len, (Str_CompareFn) Str_compare);
+}
+/**
+ * @brief sort array of strings with quick sort algorithm
+ *
+ * @param strs array of strings
+ * @param len length of array
+ * @return const char** return address of strs
+ */
+const char** Str_quickSort(const char** strs, Str_LenType len) {
+ return Str_quickSortBlock(strs, 0, (Mem_LenType) len - 1, (Str_CompareFn) Str_compare);
+}
+/**
+ * @brief sort array of strings in reverse order, use selection sort algorithm
+ *
+ * @param strs array of strings
+ * @param len length of array
+ * @return char** return address of strs
+ */
+const char** Str_sortReverse(const char** strs, Str_LenType len) {
+ return Str_selectionSortBlock(strs, (Mem_LenType) len, (Str_CompareFn) Str_compareInverse);
+}
+/**
+ * @brief sort array of strings in reverse order, use quick sort algorithm
+ *
+ * @param strs array of strings
+ * @param len length of array
+ * @return char** return address of strs
+ */
+const char** Str_quickSortReverse(const char** strs, Str_LenType len) {
+ return Str_quickSortBlock(strs, 0, (Mem_LenType) len - 1, (Str_CompareFn) Str_compareInverse);
+}
+/**
+ * @brief Split string into 2D character array
+ *
+ * @param src address of string
+ * @param separator separator character
+ * @param strs address of 2D array
+ * @param rowLen length of each row
+ * @param len length of rows
+ * @return Str_LenType return number of strs found
+ */
+Str_LenType Str_split(const char* src, char separator, char* strs, Str_LenType rowLen, Str_LenType len) {
+ Str_LenType count = 0;
+ Str_LenType tmpLen;
+ char* end;
+
+ // for null character
+ rowLen--;
+
+ if (*src != __Str_Null) {
+ while ((end = Str_indexOf(src, separator)) != NULL && len-- > 0) {
+ tmpLen = (Str_UNum)(end - src);
+ // check it's enough space for string
+ if (rowLen < tmpLen) {
+ tmpLen = rowLen;
+ }
+ Str_copyFix(strs, src, tmpLen);
+ strs[tmpLen] = __Str_Null;
+ strs += rowLen + 1;
+ src = end + 1;
+ count++;
+ }
+
+ if (len > 0) {
+ end = Str_indexOfNull(src);
+ tmpLen = (Str_UNum)(end - src);
+ if (rowLen < tmpLen) {
+ tmpLen = rowLen;
+ }
+ Str_copyFix(strs, src, tmpLen);
+ strs[tmpLen] = __Str_Null;
+ count++;
+ }
+ }
+
+ return count;
+}
+/**
+ * @brief Split string into character pointer array
+ *
+ * @param src address of string
+ * @param separator separator character
+ * @param strs address of array
+ * @param len length of array
+ * @param setNull if it's 1 change base string and replace separator characters with null
+ * @return Str_LenType return number of strs found
+ */
+Str_LenType Str_splitPtr(char* src, char separator, char** strs, Str_LenType len, uint8_t setNull) {
+ Str_UNum count = 0;
+ char* end;
+
+ if (*src != __Str_Null) {
+ while ((end = Str_indexOf(src, separator)) != NULL && len-- > 0) {
+ *strs = src;
+ if (setNull) {
+ *end = __Str_Null;
+ }
+ strs++;
+ src = end + 1;
+ count++;
+ }
+
+ if (len > 0) {
+ *strs = src;
+ count++;
+ }
+ }
+
+ return count;
+}
+/**
+ * @brief Split string in serialize mode, put in in loop until return NULL
+ * it's similar to strtok
+ * remember it will replace separator characters with null
+ *
+ * @param src address of base string
+ * @param separator separator character
+ * @param ptr temporay character pointer
+ * @return char* return next token or NULL if there is any
+ */
+char* Str_splitToken(char* src, char separator, char** ptr, uint8_t setNull) {
+ char* end;
+
+ if (src == NULL || *src == __Str_Null) {
+ *ptr = NULL;
+ return NULL;
+ }
+
+ if (*ptr < src) {
+ *ptr = src;
+ }
+
+ src = *ptr;
+ if (**ptr != __Str_Null) {
+ end = Str_indexOf(*ptr, separator);
+ if (end) {
+ *ptr = end + 1;
+ if (setNull) {
+ *end = __Str_Null;
+ }
+ }
+ else {
+ *ptr = Str_indexOfNull(*ptr);
+ }
+ }
+
+ return src;
+}
+/**
+ * @brief find position of a character in string
+ *
+ * @param str address of string
+ * @param c searching character
+ * @return Str_LenType position of character
+ */
+Str_LenType Str_posOf(const char* str, char c) {
+ return (Str_LenType) (Str_indexOf(str, c) - str);
+}
+/**
+ * @brief find position of a character in string with reverse search
+ *
+ * @param str address of string
+ * @param c searching character
+ * @return Str_LenType position of charachter
+ */
+Str_LenType Str_lastPosOf(const char* str, char c) {
+ return (Str_LenType) (Str_lastIndexOf(str, c) - str);
+}
+/**
+ * @brief find position of start of word in string
+ *
+ * @param str address of string
+ * @param word searching string
+ * @return Str_LenType
+ */
+Str_LenType Str_posOfStr(const char* str, const char* word) {
+ return (Str_LenType) (Str_indexOfStr(str, word) - str);
+}
+/**
+ * @brief find string in array of strings with linear search algorithm
+ *
+ * @param strs array of strings
+ * @param len length of strs
+ * @param str searching string
+ * @return Str_LenType position of str in strs
+ */
+Str_LenType Str_multiCompare(const char** strs, Str_LenType len, const char* str) {
+ return Str_linearSearch(strs, len, str, (Str_CompareFn) Str_compare);
+}
+/**
+ * @brief find string in array of strings with binary search algorithm
+ *
+ * @param strs array of strings
+ * @param len length of strs
+ * @param str searching string
+ * @return Str_LenType position of str in strs
+ */
+Str_LenType Str_multiCompareSorted(const char** strs, Str_LenType len, const char* str) {
+ return Str_binarySearch(strs, len, str, (Str_CompareFn) Str_compare);
+}
+/**
+ * @brief find first string that found in array of strings
+ *
+ * @param src addres of source string
+ * @param strs array of strings that we want find in source string
+ * @param len length of strs
+ * @param result index and position of finded string
+ * @return const char* address of finded string in source string
+ */
+const char* Str_findStrs(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result) {
+ Str_LenType index;
+
+ while (*src != __Str_Null) {
+ for (index = 0; index < len; index++) {
+ if (Str_compareWord(src, strs[index]) == 0) {
+ result->IndexOf = src;
+ result->Position = index;
+ return src;
+ }
+ }
+ src++;
+ }
+ return NULL;
+}
+/**
+ * @brief find first string that found in array of strings with binary search algorithm
+ *
+ * @param src addres of source string
+ * @param strs array of strings that we want find in source string
+ * @param len length of strs
+ * @param result index and position of finded string
+ * @return const char* address of finded string in source string
+ */
+const char* Str_findStrsSorted(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result) {
+ Str_LenType index;
+ Str_LenType pos;
+
+ while (*src != __Str_Null) {
+ for (index = 0; index < len; index++) {
+ if ((pos = Str_binarySearch(strs, len, src, (Str_CompareFn) Str_compareWord)) != -1) {
+ result->IndexOf = src;
+ result->Position = pos;
+ return src;
+ }
+ }
+ src++;
+ }
+ return NULL;
+}
+/**
+ * @brief find first string that found in array of strings
+ *
+ * @param src addres of source string
+ * @param strs array of strings that we want find in source string
+ * @param len length of strs
+ * @param result index and position of finded string
+ * @param srcLen len of source string
+ * @return const char* address of finded string in source string
+ */
+const char* Str_findStrsFix(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result, Str_LenType srcLen) {
+ Str_LenType index;
+
+ while (*src != __Str_Null && srcLen-- > 0) {
+ for (index = 0; index < len; index++) {
+ if (Str_compareWord(src, strs[index]) == 0) {
+ result->IndexOf = src;
+ result->Position = index;
+ return src;
+ }
+ }
+ src++;
+ }
+ return NULL;
+}
+/**
+ * @brief find first string that found in array of strings with binary search algorithm
+ *
+ * @param src addres of source string
+ * @param strs array of strings that we want find in source string
+ * @param len length of strs
+ * @param result index and position of finded string
+ * @param srcLen len of source string
+ * @return const char* address of finded string in source string
+ */
+const char* Str_findStrsSortedFix(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result, Str_LenType srcLen) {
+ Str_LenType index;
+ Str_LenType pos;
+
+ while (*src != __Str_Null && srcLen-- > 0) {
+ for (index = 0; index < len; index++) {
+ if ((pos = Str_binarySearch(strs, len, src, (Str_CompareFn) Str_compareWord)) >= 0) {
+ result->IndexOf = src;
+ result->Position = pos;
+ return src;
+ }
+ }
+ src++;
+ }
+ return NULL;
+}
+/**
+ * @brief parse string text into real values
+ * ex: "\"Test\"" -> "Test"
+ * ex: "\"Line1 \\nLine 2\"" -> "Line 1 \nLine 2"
+ *
+ * @param string
+ * @param str
+ * @return Str_LenType
+ */
+Str_LenType Str_parseString(const char* string, char* str) {
+ unsigned int unicodeChar;
+ char* pSrc = str;
+ // check start double quote
+ if (*string++ != '"') {
+ return -1;
+ }
+ // parse string
+ while (*string != '\0' && *string != '"') {
+ if (*string == '\\') {
+ string++;
+ switch (*string) {
+ case '"': // quotaion mark
+ *str = '"';
+ break;
+ case '\\': // reverse solidus
+ *str = '\\';
+ break;
+ case '/': // solidus
+ *str = '/';
+ break;
+ case 'b': // backspace
+ *str = '\b';
+ break;
+ case 'f': // formfeed
+ *str = '\f';
+ break;
+ case 'n': // line feed
+ *str = '\n';
+ break;
+ case 'r': // carriage return
+ *str = '\r';
+ break;
+ case 't': // tab
+ *str = '\t';
+ break;
+ case 'u': // 4x HEX Digit
+ if (Str_convertUNumFix(++string, &unicodeChar, Str_Hex, 4) == Str_Ok) {
+ char temp = (char) (unicodeChar >> 8);
+ string += 3;
+ if (temp != __Str_Null) {
+ *str++ = temp;
+ }
+ *str = (char) unicodeChar;
+ }
+ else {
+ return -1;
+ }
+ break;
+ default: // not support
+ return -1;
+ }
+ }
+ else {
+ *str = *string;
+ }
+ str++;
+ string++;
+ }
+ // check end double quote
+ if (*string != '"') {
+ return -1;
+ }
+ // return len of str
+ *str = __Str_Null;
+ return (Str_LenType)(str - pSrc);
+}
+/**
+ * @brief parse string text into real values
+ * ex: "\"Test\"" -> "Test"
+ * ex: "\"Line1 \\nLine 2\"" -> "Line 1 \nLine 2"
+ *
+ * @param str
+ * @return Str_LenType
+ */
+Str_LenType Str_fromString(char* str) {
+ return Str_parseString(str, str);
+}
+/**
+ * @brief convert str into valid string format for serialize
+ * ex: "Text\\n" -> "\"Text\\n\""
+ *
+ * @param str
+ * @param string
+ * @return char* return last index of string
+ */
+char* Str_convertString(const char* str, char* string) {
+ // set first double quote
+ *string++ = '"';
+ // convert str
+ while (*str != __Str_Null) {
+ if (*str < ' ' || *str == '\\' || *str == '/' || *str == '"') {
+ *string++ = '\\';
+ switch (*str) {
+ case '"':
+ *string = '"';
+ break;
+ case '\n':
+ *string = 'n';
+ break;
+ case '\r':
+ *string = 'r';
+ break;
+ case '\t':
+ *string = 't';
+ break;
+ case '\\':
+ *string = '\\';
+ break;
+ case '/':
+ *string = '/';
+ break;
+ case '\b':
+ *string = 'b';
+ break;
+ case '\f':
+ *string = 'f';
+ break;
+ default:
+ // ignore character
+ string--;
+ break;
+ }
+ }
+ else {
+ *string = *str;
+ }
+ string++;
+ str++;
+ }
+ // set second double qoute
+ *string++ = '"';
+ *string = __Str_Null;
+ return string;
+}
+/**
+ * @brief convert str into valid string format for serialize
+ * ex: "Text\n" -> "\"Text\\n\""
+ *
+ * @param str
+ * @param string
+ * @param len number of characters for convert
+ * @return char* return last index of string
+ */
+char* Str_convertStringFix(const char* str, char* string, Str_LenType len) {
+ // set first double quote
+ *string++ = '"';
+ // convert str
+ while (*str != __Str_Null && len-- > 0) {
+ if (*str < ' ' || *str == '\\' || *str == '/' || *str == '"') {
+ *string++ = '\\';
+ switch (*str) {
+ case '"':
+ *string = '"';
+ break;
+ case '\n':
+ *string = 'n';
+ break;
+ case '\r':
+ *string = 'r';
+ break;
+ case '\t':
+ *string = 't';
+ break;
+ case '\\':
+ *string = '\\';
+ break;
+ case '/':
+ *string = '/';
+ break;
+ case '\b':
+ *string = 'b';
+ break;
+ case '\f':
+ *string = 'f';
+ break;
+ default:
+ // ignore character
+ string--;
+ break;
+ }
+ }
+ else {
+ *string = *str;
+ }
+ string++;
+ str++;
+ }
+ // set second double qoute
+ *string++ = '"';
+ *string = __Str_Null;
+ return string;
+}
+/**
+ * @brief convert a number into string with specific base index and length
+ *
+ * @param num number that we want convert
+ * @param base base index
+ * @param minLen minimum length of result string
+ * @param str address destination string
+ * @return Str_LenType return length of str
+ */
+Str_LenType Str_parseNum(Str_Num num, Str_Radix base, Str_LenType minLen, char* str) {
+ if (num < 0){
+ *str++ = '-';
+ num *= -1;
+ return Str_parseUNum((Str_UNum) num, base, minLen, str) + 1;
+ }
+ else {
+ return Str_parseUNum((Str_UNum) num, base, minLen, str);
+ }
+}
+/**
+ * @brief convert a unsigned number into string with specific base index and length
+ *
+ * @param num number that we want convert
+ * @param base base index
+ * @param minLen minimum length of result string
+ * @param str address destination string
+ * @return Str_LenType return length of str
+ */
+Str_LenType Str_parseUNum(Str_UNum num, Str_Radix base, Str_LenType minLen, char* str) {
+ Str_LenType count = 0;
+ char* pStr = str;
+ char temp;
+ do {
+ temp = num % (Str_LenType) base;
+ *pStr++ = temp < __Str_Decimal ? (temp + __Str_0) : (temp + 0x37);
+ count++;
+ num /= base;
+ } while (num != 0 || count < minLen);
+ Mem_reverse(str, (Mem_LenType) count);
+ *pStr = __Str_Null;
+ return count;
+}
+/**
+ * @brief convert a string into number
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @param base base index
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertNum(const char* str, Str_Num* num, Str_Radix base) {
+ return Str_convertNumFix(str, num, base, __Str_MaxLength);
+}
+/**
+ * @brief convert a string into unsigned number
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @param base base index
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertUNum(const char* str, Str_UNum* num, Str_Radix base) {
+ return Str_convertUNumFix(str, num, base, __Str_MaxLength);
+}
+/**
+ * @brief convert a string into number with fixed length
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @param base base index
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertNumFix(const char* str, Str_Num* num, Str_Radix base, Str_LenType len) {
+ if (*str == '-'){
+ Str_Result res;
+ res = Str_convertUNumFix(++str, (Str_UNum*) num, base, --len);
+ *num *= -1;
+ return res;
+ }
+ else {
+ return Str_convertUNumFix(str, (Str_UNum*) num, base, len);
+ }
+}
+/**
+ * @brief convert a string into unsigned number with fixed length
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @param base base index
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertUNumFix(const char* str, Str_UNum* num, Str_Radix base, Str_LenType len) {
+ Str_UNum temp;
+ *num = 0;
+ while (*str != __Str_Null && len-- > 0){
+ if (*str >= __Str_0 && *str <= __Str_9){
+ temp = *str - __Str_0;
+ }
+ else if (*str >= 'A' && *str <= 'Z'){
+ temp = *str - 0x37;
+ }
+ else if (*str >= 'a' && *str <= 'z'){
+ temp = *str - 0x57;
+ }
+ else {
+ return Str_Error;
+ }
+ if (temp >= base){
+ return Str_Error;
+ }
+ *num = *num * base + temp;
+ str++;
+ }
+ return Str_Ok;
+}
+#if STR_ENABLE_LONG_NUMBER
+/**
+ * @brief convert a long number into string with specific base index and length
+ *
+ * @param num number that we want convert
+ * @param base base index
+ * @param minLen minimum length of result string
+ * @param str address destination string
+ * @return Str_LenType return length of str
+ */
+Str_LenType Str_parseLong(Str_Long num, Str_Radix base, Str_LenType minLen, char* str) {
+ if (num < 0){
+ *str++ = '-';
+ num *= -1;
+ return Str_parseULong((Str_ULong) num, base, minLen, str) + 1;
+ }
+ else {
+ return Str_parseULong((Str_ULong) num, base, minLen, str);
+ }
+}
+/**
+ * @brief convert a unsigned long number into string with specific base index and length
+ *
+ * @param num number that we want convert
+ * @param base base index
+ * @param minLen minimum length of result string
+ * @param str address destination string
+ * @return Str_LenType return length of str
+ */
+Str_LenType Str_parseULong(Str_ULong num, Str_Radix base, Str_LenType minLen, char* str) {
+ Str_LenType count = 0;
+ char* pStr = str;
+ char temp;
+ do {
+ temp = num % (Str_LenType) base;
+ *pStr++ = temp < __Str_Decimal ? (temp + __Str_0) : (temp + 0x37);
+ count++;
+ num /= base;
+ } while (num != 0 || count < minLen);
+ Mem_reverse(str, (Mem_LenType) count);
+ *pStr = __Str_Null;
+ return count;
+}
+/**
+ * @brief convert a string into long number
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @param base base index
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertLong(const char* str, Str_Long* num, Str_Radix base) {
+ return Str_convertLongFix(str, num, base, __Str_MaxLength);
+}
+/**
+ * @brief convert a string into unsigned long number
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @param base base index
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertULong(const char* str, Str_ULong* num, Str_Radix base) {
+ return Str_convertULongFix(str, num, base, __Str_MaxLength);
+}
+/**
+ * @brief convert a string into long number with fixed length
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @param base base index
+ * @param len
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertLongFix(const char* str, Str_Long* num, Str_Radix base, Str_LenType len) {
+ if (*str == '-'){
+ Str_Result res;
+ res = Str_convertULongFix(++str, (Str_ULong*) num, base, --len);
+ *num *= -1;
+ return res;
+ }
+ else {
+ return Str_convertULongFix(str, (Str_ULong*) num, base, len);
+ }
+}
+/**
+ * @brief convert a string into unsigned long number with fixed length
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @param base base index
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertULongFix(const char* str, Str_ULong* num, Str_Radix base, Str_LenType len) {
+ Str_UNum temp;
+ *num = 0;
+ while (*str != __Str_Null && len-- > 0){
+ if (*str >= __Str_0 && *str <= __Str_9){
+ temp = *str - __Str_0;
+ }
+ else if (*str >= 'A' && *str <= 'Z'){
+ temp = *str - 0x37;
+ }
+ else if (*str >= 'a' && *str <= 'z'){
+ temp = *str - 0x57;
+ }
+ else {
+ return Str_Error;
+ }
+ if (temp >= base){
+ return Str_Error;
+ }
+ *num = *num * base + temp;
+ str++;
+ }
+ return Str_Ok;
+}
+#endif // STR_ENABLE_LONG_NUMBER
+/**
+ * @brief convert float number into string
+ *
+ * @param num float number
+ * @param str address of output string
+ * @return Str_LenType
+ */
+Str_LenType Str_parseFloat(float num, char* str) {
+ int numInt = (int) num;
+ Str_LenType len;
+ len = Str_parseNum(numInt, __Str_Decimal, STR_NORMAL_LEN, str);
+ str = str + len;
+ num = num - numInt;
+ if (num != 0) {
+ *str++ = '.';
+ len++;
+ if (num < 0){
+ num *= -1;
+ }
+ numInt = (int) num;
+ while (num != 0) {
+ num *= __Str_Decimal;
+ numInt = (int) num;
+ *str++ = numInt + __Str_0;
+ len++;
+ num -= numInt;
+ }
+ }
+ *str = __Str_Null;
+ return len;
+}
+/**
+ * @brief convert float number into string
+ *
+ * @param num float number
+ * @param str address of output string
+ * @param decimalLen resolution of floating part
+ * @return Str_LenType
+ */
+Str_LenType Str_parseFloatFix(float num, char* str, Str_LenType decimalLen) {
+ int pow = decimalLen;
+ int numInt = (int) num;
+ Str_LenType len;
+ len = Str_parseNum(numInt, __Str_Decimal, STR_NORMAL_LEN, str);
+ if (decimalLen != 0) {
+ str = str + len;
+ *str++ = '.';
+ num = num - numInt;
+ if (num < 0){
+ num *= -1;
+ }
+ while (pow-- != 0){
+ num *= __Str_Decimal;
+ }
+ len += Str_parseNum((int) num, __Str_Decimal, STR_NORMAL_LEN, str) + 1;
+ }
+ return len;
+}
+/**
+ * @brief convert a string into float number
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertFloat(const char* str, float* num) {
+ return Str_convertFloatFix(str, num, Str_len(str));
+}
+/**
+ * @brief convert a string into float number with fixed length
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @param len number of charactres for convert
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertFloatFix(const char* str, float* num, Str_LenType len) {
+ const char* pDot = Str_indexOf(str, '.');
+ float temp;
+ int numInt;
+ Str_LenType strLen;
+ if (pDot == NULL){
+ pDot = Mem_indexOf(str, __Str_Null, __Str_MaxLength);
+ }
+ strLen = (Str_LenType)(pDot - str);
+ if (strLen > len){
+ strLen = len;
+ }
+ if (Str_convertNumFix(str, &numInt, __Str_Decimal, strLen) == Str_Ok){
+ *num = numInt;
+ if (*pDot != __Str_Null){
+ len -= strLen + 1;
+ if (Str_convertNumFix(++pDot, &numInt, Str_Decimal, len) != Str_Ok){
+ return Str_Error;
+ }
+ temp = numInt;
+ while (len-- > 0) {
+ temp /= __Str_Decimal;
+ }
+ *num = *num < 0 ? *num - temp : *num + temp;
+ }
+ return Str_Ok;
+ }
+ return Str_Error;
+}
+/**
+ * @brief ignore all characters below than space character (' ' = 0x20)
+ *
+ * @param str
+ * @return char* return address of first character
+ */
+char* Str_ignoreWhitespace(const char* str) {
+ while (*str <= ' ' && *str != __Str_Null) {
+ str++;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ignore all characters above and equal than space character (' ' = 0x20)
+ *
+ * @param str
+ * @return char* return address of first whitespace
+ */
+char* Str_ignoreCharacters(const char* str) {
+ while (*str >= ' ' && *str != __Str_Null) {
+ str++;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ignore all a-z,A-Z,0-9 characters
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_ignoreAlphaNumeric(const char* str) {
+ while (*str != __Str_Null &&
+ ((*str >= '0' && *str <= '9') ||
+ (*str >= 'A' && *str <= 'Z') ||
+ (*str >= 'a' && *str <= 'z'))) {
+ str++;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ignore all alphabet characters, A-Z,a-z
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_ignoreAlphabet(const char* str) {
+ while (*str != __Str_Null &&
+ ((*str >= 'A' && *str <= 'Z') ||
+ (*str >= 'a' && *str <= 'z'))) {
+ str++;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ignore all numeric characters, 0-9
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_ignoreNumeric(const char* str) {
+ while (*str != __Str_Null && (*str >= '0' && *str <= '9')) {
+ str++;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ignore all special characters
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_ignoreSpecialCharacters(const char* str) {
+ while (*str != __Str_Null &&
+ ((*str >= '!' && *str <= '/') ||
+ (*str >= ':' && *str <= '@') ||
+ (*str >= '[' && *str <= '`') ||
+ (*str >= '{' && *str <= '~'))) {
+ str++;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ignore all following characters: 0-9,A-Z,a-z, '-', '_'
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_ignoreNameCharacters(const char* str) {
+ while (*str != __Str_Null &&
+ ((*str >= '0' && *str <= '9') ||
+ (*str >= 'A' && *str <= 'Z') ||
+ (*str >= 'a' && *str <= 'z') ||
+ *str == '-' || *str == '_')) {
+ str++;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ingore following characters: ':'-'@','#'-'&','!'
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_ignoreCommandCharacters(const char* str) {
+ while (*str != __Str_Null &&
+ ((*str >= ':' && *str <= '@') ||
+ (*str >= '#' && *str <= '&') ||
+ *str == '!')) {
+ str++;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ignore characters in given str with custom role
+ *
+ * @param str
+ * @param cmp
+ * @return char*
+ */
+char* Str_ignore(const char* str, Str_IgnoreRoleFn cmp) {
+ while (*str != __Str_Null && (char) cmp(*str)) {
+ str++;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ignore whitespaces from last of string
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_ignoreWhitespaceReverse(const char* str) {
+ str = Str_indexOfEnd(str);
+ while (*str <= ' ' && *str != __Str_Null) {
+ str--;
+ }
+ return (char*) str;
+}
+/**
+ * @brief ignore characters from last of string
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_ignoreCharactersReverse(const char* str) {
+ str = Str_indexOfEnd(str);
+ while (*str > ' ' && *str != __Str_Null) {
+ str--;
+ }
+ return (char*) str;
+}
+/**
+ * @brief change all characters into upper case
+ *
+ * @param str
+ * @return char*
+ */
+void Str_upperCase(char* str) {
+ while (*str != __Str_Null) {
+ if (*str >= 'a' && *str <= 'z') {
+ *str = *str - 32;
+ }
+ str++;
+ }
+}
+/**
+ * @brief change all characters into upper case, with fixed Length
+ *
+ * @param str
+ * @param len
+ * @return char*
+ */
+void Str_upperCaseFix(char* str, Str_LenType len) {
+ while (*str != __Str_Null && len-- > 0) {
+ if (*str >= 'a' && *str <= 'z') {
+ *str = *str - 32;
+ }
+ str++;
+ }
+}
+/**
+ * @brief change all characters into lower case
+ *
+ * @param str
+ */
+void Str_lowerCase(char* str) {
+ while (*str != __Str_Null) {
+ if (*str >= 'A' && *str <= 'Z') {
+ *str = *str + 32;
+ }
+ str++;
+ }
+}
+/**
+ * @brief change all characters into lower case with fix Length
+ *
+ * @param str
+ */
+void Str_lowerCaseFix(char* str, Str_LenType len) {
+ while (*str != __Str_Null && len-- > 0) {
+ if (*str >= 'A' && *str <= 'Z') {
+ *str = *str + 32;
+ }
+ str++;
+ }
+}
+/**
+ * @brief remove all whitespace in left of string
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_trimLeft(char* str) {
+ char* pEnd = Str_ignoreWhitespace(str);
+ if (pEnd != str) {
+ Mem_move(str, pEnd, Str_len(str) - (Mem_LenType)(pEnd - str) + 1);
+ }
+ return str;
+}
+/**
+ * @brief remove all whitespaces in right of string
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_trimRight(char* str) {
+ char* pEnd = Str_ignoreWhitespaceReverse(str) + 1;
+ *pEnd = __Str_Null;
+ return str;
+}
+/**
+ * @brief trim left and right of string
+ *
+ * @param str
+ * @return char*
+ */
+char* Str_trim(char* str) {
+ Str_trimRight(str);
+ Str_trimLeft(str);
+ return str;
+}
+/**
+ * @brief remove all backspace ('\b') characters and left character
+ * ex: "ABCD\bER" -> "ABCER"
+ *
+ * @param str
+ * @return Str_LenType return new length
+ */
+Str_LenType Str_removeBackspace(char* str) {
+ Str_LenType len = Str_len(str);
+ if (len > 0) {
+ char* pStr = str + len - 1;
+ while (str < pStr) {
+ if (*pStr-- == '\b') {
+ Mem_move(pStr, pStr + 2, len - (Mem_LenType)(pStr - str));
+ len -= 2;
+ }
+ }
+ if (*pStr == '\b') {
+ Mem_move(pStr, pStr + 1, len - (Mem_LenType)(pStr - str));
+ len -= 1;
+ }
+ }
+ return len;
+}
+/**
+ * @brief remove all backspace ('\b') characters and left character with fix len
+ * ex: "ABCD\bER" -> "ABCER"
+ *
+ * @param str
+ * @param len
+ * @return Str_LenType return new length
+ */
+Str_LenType Str_removeBackspaceFix(char* str, Str_LenType len) {
+ if (len > 0) {
+ char* pStr = str + len - 1;
+ while (str < pStr) {
+ if (*pStr-- == '\b') {
+ Mem_move(pStr, pStr + 2, len - (Mem_LenType)(pStr - str));
+ len -= 2;
+ }
+ }
+ if (*pStr == '\b') {
+ Mem_move(pStr, pStr + 1, len - (Mem_LenType)(pStr - str));
+ len -= 1;
+ }
+ }
+ return len;
+}
+#if STR_ENABLE_DOUBLE
+/**
+ * @brief convert double number into string
+ *
+ * @param num float number
+ * @param str address of output string
+ * @return Str_LenType
+ */
+Str_LenType Str_parseDouble(double num, char* str) {
+ int numInt = (int) num;
+ Str_LenType len;
+ len = Str_parseNum(numInt, __Str_Decimal, STR_NORMAL_LEN, str);
+ str = str + len;
+ num = num - numInt;
+ if (num != 0) {
+ *str++ = '.';
+ len++;
+ if (num < 0){
+ num *= -1;
+ }
+ numInt = (int) num;
+ while (num != 0) {
+ num *= __Str_Decimal;
+ numInt = (int) num;
+ *str++ = numInt + __Str_0;
+ len++;
+ num -= numInt;
+ }
+ }
+ *str = __Str_Null;
+ return len;
+}
+/**
+ * @brief convert double number into string
+ *
+ * @param num float number
+ * @param str address of output string
+ * @param decimalLen resolution of floating part
+ * @return Str_LenType
+ */
+Str_LenType Str_parseDoubleFix(double num, char* str, Str_LenType decimalLen) {
+ int pow = decimalLen;
+ int numInt = (int) num;
+ Str_LenType len;
+ len = Str_parseNum(numInt, __Str_Decimal, STR_NORMAL_LEN, str);
+ if (decimalLen != 0) {
+ str = str + len;
+ *str++ = '.';
+ num = num - numInt;
+ if (num < 0){
+ num *= -1;
+ }
+ while (pow-- != 0){
+ num *= __Str_Decimal;
+ }
+ len += Str_parseNum((int) num, __Str_Decimal, STR_NORMAL_LEN, str) + 1;
+ }
+ return len;
+}
+
+/**
+ * @brief convert a string into double number
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertDouble(const char* str, double* num) {
+ return Str_convertDoubleFix(str, num, Str_len(str));
+}
+/**
+ * @brief convert a string into double number with fixed length
+ *
+ * @param str address of source string
+ * @param num address of output number
+ * @return Str_Result result of convert
+ */
+Str_Result Str_convertDoubleFix(const char* str, double* num, Str_LenType len) {
+ const char* pDot = Str_indexOf(str, '.');
+ double temp;
+ int numInt;
+ Str_LenType strLen;
+ if (pDot == NULL){
+ pDot = Mem_indexOf(str, __Str_Null, __Str_MaxLength);
+ }
+ strLen = (Str_LenType)(pDot - str);
+ if (strLen > len){
+ strLen = len;
+ }
+ if (Str_convertNumFix(str, &numInt, __Str_Decimal, strLen) == Str_Ok){
+ *num = numInt;
+ if (*pDot != __Str_Null){
+ len -= strLen + 1;
+ if (Str_convertNumFix(++pDot, &numInt, __Str_Decimal, len) != Str_Ok){
+ return Str_Error;
+ }
+ temp = numInt;
+ while (len-- > 0) {
+ temp /= __Str_Decimal;
+ }
+ *num = *num < 0 ? *num - temp : *num + temp;
+ }
+ return Str_Ok;
+ }
+ return Str_Error;
+}
+
+#endif // STR_ENABLE_DOUBLE
+/**
+ * @brief get first number that found in string
+ *
+ * @param str address of source string
+ * @param num number that found
+ * @param numPos index of number that found
+ * @return Str_Result result of searching for number
+ */
+Str_Result Str_getNum(const char* str, int* num, const char** numPos) {
+ const char* baseStr = str;
+ str = Str_findDigit(str);
+ if (str != NULL){
+ if (baseStr < str && *(str - 1) == '-'){
+ str--;
+ }
+ *numPos = str;
+ if (Str_convertNumFix(str, num, __Str_Decimal, (Str_LenType) (Str_findLastDigit(str) - str + 1)) == Str_Ok){
+ return Str_Ok;
+ }
+ }
+ return Str_Error;
+}
+/**
+ * @brief get first unsigned number that found in string
+ *
+ * @param str address of source string
+ * @param num number that found
+ * @param numPos index of number that found
+ * @return Str_Result result of searching for number
+ */
+Str_Result Str_getUNum(const char* str, unsigned int* num, const char** numPos) {
+ str = Str_findDigit(str);
+ if (str != 0){
+ *numPos = str;
+ if (Str_convertUNumFix(str, num, __Str_Decimal, (Str_LenType) (Str_findLastDigit(str) - str + 1)) == Str_Ok){
+ return Str_Ok;
+ }
+ }
+ return Str_Error;
+}
+/**
+ * @brief get first float number that found in string
+ *
+ * @param str address of source string
+ * @param num number that found
+ * @param numPos index of number that found
+ * @return Str_Result result of searching for number
+ */
+Str_Result Str_getFloat(const char* str, float* num, const char** numPos) {
+ const char* pDot = str;
+ str = Str_findDigit(str);
+ if (str != NULL){
+ if (pDot < str && *(str - 1) == '-'){
+ str--;
+ }
+ pDot = Str_findLastDigit(str) + 1;
+ if (*(pDot) == '.'){
+ pDot = Str_findLastDigit(pDot);
+ pDot = pDot == NULL ? Str_indexOfEnd(str) : pDot + 1;
+ }
+ *numPos = str;
+ if (Str_convertFloatFix(str, num, pDot - str) == Str_Ok){
+ return Str_Ok;
+ }
+ }
+ return Str_Error;
+}
+/**
+ * @brief get token from an string
+ * ex: getToken("123,ABCD,48", ',', 1, token);
+ * assert(token, "ABCD");
+ *
+ * @param str
+ * @param separator
+ * @param index
+ * @param token
+ * @return Str_Result
+ */
+Str_Result Str_getToken(const char* str, char separator, Str_LenType index, char* token) {
+ return Str_getTokenFix(str, separator, index, token, STR_NORMAL_LEN);
+}
+/**
+ * @brief get token from an string
+ * ex: getTokenFix("123,ABCD,48", ',', 1, token, sizeof(token) - 1);
+ * assert(token, "ABCD");
+ *
+ * @param str
+ * @param separator
+ * @param index
+ * @param token
+ * @param len
+ * @return Str_Result
+ */
+Str_Result Str_getTokenFix(const char* str, char separator, Str_LenType index, char* token, Str_LenType len) {
+ if ((str = Str_indexOfAt(str, separator, index)) != NULL) {
+ char* end;
+ Mem_LenType tokenLen;
+ if (*str == separator) {
+ str++;
+ }
+ if ((end = Str_indexOf(str, separator)) == NULL) {
+ end = Str_indexOfNull(str);
+ }
+ tokenLen = (Mem_LenType)(end - str);
+ if (STR_NORMAL_LEN != len && tokenLen >= len) {
+ tokenLen = len;
+ }
+ Mem_copy(token, str, tokenLen);
+ token[tokenLen] = __Str_Null;
+ return Str_Ok;
+ }
+
+ return Str_Error;
+}
+/**
+ * @brief swap address of two string
+ *
+ * @param itemA string 1
+ * @param itemB string 2
+ */
+void Str_swap(const char** itemA, const char** itemB) {
+ const char* temp = *itemA;
+ *itemA = *itemB;
+ *itemB = temp;
+}
+
+Str_LenType Str_partition(const char** items, Str_LenType low, Str_LenType high, Str_CompareFn cmp) {
+ const char* pivot = items[high]; // pivot
+ Str_LenType i = (low - 1); // Index of smaller element
+ Str_LenType j;
+ for (j = low; j <= high - 1; j++)
+ {
+ // If current element is smaller than the pivot
+ if (cmp(items[j], pivot) < 0)
+ {
+ i++; // increment index of smaller element
+ Str_swap(&items[i], &items[j]);
+ }
+ }
+ Str_swap(&items[i + 1], &items[high]);
+ return (i + 1);
+}
+/**
+ * @brief run quick sort algorithm for items with given compare Fntion
+ *
+ * @param items array of strings
+ * @param low position of start
+ * @param high position of end
+ * @param cmp address of compare Fntion
+ * @return char** return items
+ */
+const char** Str_quickSortBlock(const char** items, Mem_LenType low, Mem_LenType high, Str_CompareFn cmp) {
+ if (low < high) {
+ /* pi is partitioning index, arr[p] is now
+ at right place */
+ Str_LenType pi = Str_partition(items, low, high, cmp);
+
+ // Separately sort elements before
+ // partition and after partition
+ Str_quickSortBlock(items, low, pi - 1, cmp);
+ Str_quickSortBlock(items, pi + 1, high, cmp);
+ }
+ return items;
+}
+/**
+ * @brief run selection sort algorithm for item with given compare Fntion
+ *
+ * @param items array of strings
+ * @param len length of array
+ * @param cmp address of compare Fntion
+ * @return char**
+ */
+const char** Str_selectionSortBlock(const char** items, Mem_LenType len, Str_CompareFn cmp) {
+ Mem_LenType i;
+ Mem_LenType j;
+ Mem_LenType min_idx;
+
+ // One by one move boundary of unsorted sub-array
+ for (i = 0; i < len-1; i++)
+ {
+ // Find the minimum element in unsorted array
+ min_idx = i;
+ for (j = i+1; j < len; j++) {
+ if (cmp(items[j], items[min_idx]) < 0) {
+ min_idx = j;
+ }
+ }
+ // Swap the found minimum element with the first element
+ Str_swap(&items[min_idx], &items[i]);
+ }
+ return items;
+}
+/**
+ * @brief find string in array of strings
+ *
+ * @param strs array of strings
+ * @param len len of array
+ * @param str
+ * @param cmp address of comperator function
+ * @return Str_LenType index of string in array
+ */
+Str_LenType Str_linearSearch(const char** strs, Str_LenType len, const char* str, Str_CompareFn cmp) {
+ Str_LenType tempLen = len;
+ while (len--) {
+ if (cmp(str, *strs++) == 0) {
+ return tempLen - len - 1;
+ }
+ }
+ return -1;
+}
+/**
+ * @brief search a string in array of strings with binary search algorithm
+ *
+ * @param strs
+ * @param len
+ * @param str
+ * @param cmp
+ * @return Str_LenType
+ */
+Str_LenType Str_binarySearch(const char** strs, Str_LenType len, const char* str, Str_CompareFn cmp) {
+ Str_LenType left = 0;
+ Str_LenType mid;
+ char result;
+
+ len--;
+
+ while (left <= len) {
+ mid = (len + left) >> 1;
+ result = cmp(str, strs[mid]);
+ // Check if str is present at mid
+ if (result == 0) {
+ return mid;
+ }
+ // If str greater, ignore left half
+ else if (result > 0) {
+ left = mid + 1;
+ }
+ // If x is smaller, ignore right half
+ else {
+ len = mid - 1;
+ }
+ }
+ // if we reach here, then element was
+ // not present
+ return -1;
+}
+/**
+ * @brief run selection sort algorithm for item with given compare Fntion, and swap function
+ *
+ * @param items array of items such as struct
+ * @param len length of array
+ * @param itemLen size of single item
+ * @param cmp address of compare Fntion
+ * @param swap address of swap function
+ * @return char**
+ */
+void* Mem_sort(void* items, Mem_LenType len, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap) {
+ Mem_LenType i;
+ Mem_LenType j;
+ Mem_LenType min_idx;
+ unsigned char* pItems = (unsigned char*) items;
+
+ // One by one move boundary of unsorted sub-array
+ len *= itemLen;
+ for (i = 0; i < len - itemLen; i += itemLen)
+ {
+ // Find the minimum element in unsorted array
+ min_idx = i;
+ for (j = i + itemLen; j < len; j += itemLen) {
+ if (cmp(&pItems[j], &pItems[min_idx], itemLen) < 0) {
+ min_idx = j;
+ }
+ }
+ // Swap the found minimum element with the first element
+ swap(&pItems[min_idx], &pItems[i], itemLen);
+ }
+ return items;
+}
+/**
+ * @brief sort array of items with quick sort algorithm
+ *
+ * @param items array of items such as struct
+ * @param len length of array
+ * @param itemLen sizeof single item
+ * @param cmp address of compare function
+ * @param swap address of swap function
+ * @return const char** return address of strs
+ */
+void* Mem_quickSort(void* items, Mem_LenType len, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap) {
+ return Mem_quickSortBlock(items, 0, (Mem_LenType) (len - 1) * itemLen, itemLen, cmp, swap);
+}
+Mem_LenType Mem_partition(void* items, Mem_LenType low, Mem_LenType high, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap) {
+ unsigned char* pItems = (unsigned char*) items;
+ const unsigned char* pivot = &pItems[high]; // pivot
+ Mem_LenType i = (low - itemLen); // Index of smaller element
+ Mem_LenType j;
+ for (j = low; j <= high - itemLen; j += itemLen)
+ {
+ // If current element is smaller than the pivot
+ if (cmp(&pItems[j], pivot, itemLen) < 0)
+ {
+ i += itemLen; // increment index of smaller element
+ swap(&pItems[i], &pItems[j], itemLen);
+ }
+ }
+ swap(&pItems[i + itemLen], &pItems[high], itemLen);
+ return (i + itemLen);
+}
+void* Mem_quickSortBlock(void* items, Mem_LenType low, Mem_LenType high, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap) {
+ if (low < high) {
+ /* pi is partitioning index, arr[p] is now
+ at right place */
+ Mem_LenType pi = Mem_partition(items, low, high, itemLen, cmp, swap);
+
+ // Separately sort elements before
+ // partition and after partition
+ Mem_quickSortBlock(items, low, pi - itemLen, itemLen, cmp, swap);
+ Mem_quickSortBlock(items, pi + itemLen, high, itemLen, cmp, swap);
+ }
+ return items;
+}
+/**
+ * @brief find item in array
+ *
+ * @param items
+ * @param len
+ * @param itemLen
+ * @param item
+ * @param cmp
+ * @return Mem_LenType
+ */
+Mem_LenType Mem_linearSearch(const void* items, Mem_LenType len, Mem_LenType itemLen, const void* item, Mem_CompareFn cmp) {
+ unsigned char* pItems = (unsigned char*) items;
+ Mem_LenType pIndex;
+ len *= itemLen;
+
+
+ for (pIndex = 0; pIndex < len; pIndex += itemLen, pItems += itemLen) {
+ if (cmp(item, pItems, itemLen) == 0) {
+ return pIndex / itemLen;
+ }
+
+ }
+ return -1;
+}
+/**
+ * @brief find item in array with binary search algorithm
+ *
+ * @param items
+ * @param len
+ * @param itemLen
+ * @param item
+ * @param cmp
+ * @return Mem_LenType
+ */
+Mem_LenType Mem_binarySearch(const void* items, Mem_LenType len, Mem_LenType itemLen, const void* item, Mem_CompareFn cmp) {
+ unsigned char* pItems = (unsigned char*) items;
+ Mem_LenType left = 0;
+ Mem_LenType mid;
+ char result;
+
+ len--;
+
+ while (left <= len) {
+ mid = (len + left) >> 1;
+ result = cmp(item, &pItems[mid * itemLen], itemLen);
+ // Check if str is present at mid
+ if (result == 0) {
+ return mid;
+ }
+ // If str greater, ignore left half
+ else if (result > 0) {
+ left = mid + 1;
+ }
+ // If x is smaller, ignore right half
+ else {
+ len = mid - 1;
+ }
+ }
+ // if we reach here, then element was
+ // not present
+ return -1;
+}
+
+#if !STR_USE_STRING_LIBRARY
+
+void* Mem_copy(void* dest, const void* src, Mem_LenType len) {
+ unsigned char* pDest = (unsigned char*) dest;
+ const unsigned char* pSrc = (const unsigned char*) src;
+ while (len-- > 0) {
+ *pDest++ = *pSrc++;
+ }
+ return dest;
+}
+char Mem_compare(const void* arr1, const void* arr2, Mem_LenType len) {
+ const unsigned char* pArr1 = (const unsigned char*) arr1;
+ const unsigned char* pArr2 = (const unsigned char*) arr2;
+ char result;
+ while (len-- > 0) {
+ if((result = *pArr1++ - *pArr2++)) {
+ break;
+ }
+ }
+ return result;
+}
+void* Mem_move(void* dest, const void* src, Mem_LenType len) {
+ unsigned char* pDest = (unsigned char*) dest;
+ const unsigned char* pSrc = (const unsigned char*) src;
+ if (len <= 0 || src == dest) {
+ return NULL;
+ }
+ if (pDest < pSrc) {
+ while (len-- > 0) {
+ *pDest++ = *pSrc++;
+ }
+ }
+ else {
+ const unsigned char* lastSrc = (const unsigned char*) (pSrc + (len - 1));
+ unsigned char* lastDest = (unsigned char*) (pDest + (len - 1));
+ while (len-- > 0) {
+ *lastDest-- = *lastSrc--;
+ }
+ }
+ return dest;
+}
+void* Mem_indexOf(const void* arr, unsigned char value, Mem_LenType len) {
+ const unsigned char* pArr = (const unsigned char*) arr;
+
+ while (len-- > 0) {
+ if (*pArr == value) {
+ return (void*) pArr;;
+ }
+ pArr++;
+ }
+ return NULL;
+}
+void* Mem_set(void* arr, unsigned char value, Mem_LenType len) {
+ unsigned char* pArr = (unsigned char*) arr;
+
+ while (len-- > 0) {
+ *pArr++ = value;
+ }
+ return arr;
+}
+
+
+
+char* Str_copy(char* dest, const char* src) {
+ char* pDest = dest;
+ while (*src != __Str_Null) {
+ *pDest++ = *src++;
+ }
+ *pDest = __Str_Null;
+ return dest;
+}
+char* Str_copyFix(char* dest, const char* src, Str_LenType len) {
+ return Mem_copy(dest, src, len);
+}
+char Str_compare(const char* str1, const char* str2) {
+ char result;
+ while (*str1 != __Str_Null) {
+ if ((result = *str1++ - *str2++)) {
+ break;
+ }
+ }
+ return result;
+}
+char Str_compareFix(const char* str1, const char* str2, Str_LenType len) {
+ return Mem_compare(str1, str2, len);
+}
+Str_LenType Str_len(const char* str) {
+ char* pStr = str;
+ while (*pStr != __Str_Null) {
+ pStr++;
+ }
+ return (Str_LenType) (pStr - str);
+}
+char* Str_indexOf(char* str, char c) {
+ while (*str != __Str_Null) {
+ if (*str == c) {
+ return str;
+ }
+ str++;
+ }
+ return NULL;
+}
+char* Str_lastIndexOf(char* str, char c) {
+ char* pStr = (char*) Mem_indexOf(str, '\'0', __Str_MaxLength) - 1;
+ while (pStr >= str) {
+ if (*pStr == c) {
+ return pStr;
+ }
+ pStr--;
+ }
+ return NULL;
+}
+char* Str_indexOfStr(char* str, char* sub) {
+ while (*str != __Str_Null && str != NULL) {
+ str = Str_indexOf(str, *sub);
+ if (Str_compareWord(str, sub) == 0) {
+ return str;
+ }
+ }
+ return NULL;
+}
+char* Str_append(char* str, char* sub) {
+ char* pStr = (char*) Mem_indexOf(str, '\'0', __Str_MaxLength);
+ Str_copy(pStr, sub);
+ return str;
+}
+
+#endif // STR_USE_STRING_LIBRARY
diff --git a/Examples/StreamOverSocket/Str/Str.h b/Examples/StreamOverSocket/Str/Str.h
new file mode 100644
index 0000000..6f24839
--- /dev/null
+++ b/Examples/StreamOverSocket/Str/Str.h
@@ -0,0 +1,329 @@
+/**
+ * @file Str.h
+ * @author Ali Mirghasemi (ali.mirghasemi1376@gmail.com)
+ * @brief this library can use to handle with ASCII strings in c
+ * @version 0.2
+ * @date 2021-08-08
+ *
+ * @copyright Copyright (c) 2021
+ *
+ */
+#ifndef _STR_UTILS_H_
+#define _STR_UTILS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define STR_VER_MAJOR 0
+#define STR_VER_MINOR 5
+#define STR_VER_FIX 0
+
+#include
+
+/********************************************************************************************/
+/* Configuration */
+/********************************************************************************************/
+#define STR_ENABLE_PARSE 1
+
+#define STR_ENABLE_CONVERT_STR 1
+
+#define MEM_MAX_LENGTH 1024
+
+#define STR_MAX_LENGTH 1024
+
+#define STR_ENABLE_LONG_NUMBER 1
+
+#define STR_ENABLE_DOUBLE 1
+
+#define STR_USE_CONST_VARIABLES 0
+
+#define STR_USE_STRING_LIBRARY 1
+
+typedef int Mem_CmpResult;
+typedef short Str_CmpResult;
+
+typedef int32_t Str_Num;
+typedef uint32_t Str_UNum;
+
+#if STR_ENABLE_LONG_NUMBER
+ typedef int64_t Str_Long;
+ typedef uint64_t Str_ULong;
+#endif
+
+typedef int16_t Str_LenType;
+typedef int16_t Mem_LenType;
+/********************************************************************************************/
+
+#if STR_USE_STRING_LIBRARY
+#include
+
+#define Mem_copy memcpy
+#define Mem_compare memcmp
+#define Mem_move memmove
+#define Mem_indexOf memchr
+#define Mem_set memset
+
+#define Str_copy strcpy
+#define Str_copyFix strncpy
+#define Str_compare strcmp
+#define Str_compareFix strncmp
+#define Str_len strlen
+#define Str_indexOf strchr
+#define Str_lastIndexOf strrchr
+#define Str_indexOfStr strstr
+#define Str_append strcat
+
+#else
+
+void* Mem_copy(void* dest, const void* src, Mem_LenType len);
+char Mem_compare(const void* arr1, const void* arr2, Mem_LenType len);
+void* Mem_move(void* dest, const void* src, Mem_LenType len);
+void* Mem_indexOf(const void* arr, unsigned char value, Mem_LenType len);
+void* Mem_set(void* arr, unsigned char value, Mem_LenType len);
+
+
+
+char* Str_copy(char* dest, const char* str);
+char* Str_copyFix(char* dest, const char* str, Str_LenType len);
+char Str_compare(const char* str1, const char* str2);
+char Str_compareFix(const char* str1, const char* str2, Str_LenType len);
+Str_LenType Str_len(const char* str);
+char* Str_indexOf(char* str, char c);
+char* Str_lastIndexOf(char* str, char c);
+char* Str_indexOfStr(char* str, char* sub);
+char* Str_append(char* str, char* sub);
+
+#endif // STR_USE_STRING_LIBRARY
+
+#define STR_NORMAL_LEN 0
+/**
+ * @brief result type for str functions
+ */
+typedef enum {
+ Str_Ok = 0,
+ Str_Error = 1,
+} Str_Result;
+/**
+ * @brief hold result of multi str find
+ */
+typedef struct {
+ const char* IndexOf;
+ Str_LenType Position;
+} Str_MultiResult;
+/**
+ * @brief custom radix for parse and convert functions
+ * other values is valid too
+ */
+typedef enum {
+ Str_Binary = 2,
+ Str_Nibble = 4,
+ Str_Octal = 8,
+ Str_Decimal = 10,
+ Str_Hex = 16,
+} Str_Radix;
+/**
+ * @brief return type for ignore role function
+ */
+typedef enum {
+ Str_NotIgnore = 0,
+ Str_Ignore = 1,
+} Str_Ignore_Result;
+/**
+ * @brief custom role for ignore characters
+ */
+typedef Str_Ignore_Result (*Str_IgnoreRoleFn) (char character);
+/**
+ * @brief string holder
+ */
+typedef struct {
+ char* Text;
+ Str_LenType Len;
+} Str;
+/**
+ * @brief const string holder
+ */
+typedef struct {
+ const char* Text;
+ Str_LenType Len;
+} StrConst;
+
+
+void* Mem_copyReverse(void* dest, const void* src, Mem_LenType len);
+void* Mem_reverse(void* arr, Mem_LenType len);
+
+char* Str_copyUntil(char* dest, const char* src, char endChar);
+char* Str_copyLine(char* dest, const char* src);
+
+char* Str_reverseIndexOf(const char* str, char c, const char* startOfStr);
+char* Str_reverseIndexOfFix(const char* str, char c, int length);
+
+char* Str_indexOfEnd(const char* str);
+char* Str_indexOfNull(const char* str);
+
+char Str_compareInverse(const char* str1, const char* str2);
+char Str_compareWord(const char* str, const char* word);
+
+char* Str_findDigit(const char* str);
+char* Str_findDigitUntil(const char* str, char endChar);
+char* Str_findDigitFix(const char* str, Str_LenType len);
+
+char* Str_findLastDigit(const char* str);
+char* Str_findLastDigitUntil(const char* str, char endChar);
+char* Str_findLastDigitFix(const char* str, Str_LenType len);
+
+char* Str_ignoreWhitespace(const char* str);
+char* Str_ignoreCharacters(const char* str);
+char* Str_ignoreAlphaNumeric(const char* str);
+char* Str_ignoreAlphabet(const char* str);
+char* Str_ignoreNumeric(const char* str);
+char* Str_ignoreSpecialCharacters(const char* str);
+char* Str_ignoreNameCharacters(const char* str);
+char* Str_ignoreCommandCharacters(const char* str);
+char* Str_ignore(const char* str, Str_IgnoreRoleFn cmp);
+
+char* Str_ignoreWhitespaceReverse(const char* str);
+char* Str_ignoreCharactersReverse(const char* str);
+
+void Str_upperCase(char* str);
+void Str_upperCaseFix(char* str, Str_LenType len);
+void Str_lowerCase(char* str);
+void Str_lowerCaseFix(char* str, Str_LenType len);
+
+char* Str_trimLeft(char* str);
+char* Str_trimRight(char* str);
+char* Str_trim(char* str);
+
+Str_LenType Str_removeBackspace(char* str);
+Str_LenType Str_removeBackspaceFix(char* str, Str_LenType len);
+
+char* Str_findReverseDigit(const char* str);
+char* Str_findReverseDigitFix(const char* str, Str_LenType len);
+
+Str_LenType Str_indexesOf(const char* str, char c, char const** indexes);
+Str_LenType Str_indexesOfFix(const char* str, char c, char const** indexes, Str_LenType len);
+Str_LenType Str_indexesOfUntil(const char* str, char c, char const** indexes, char endChar);
+
+char* Str_indexOfAt(const char* str, char c, Str_LenType num);
+char* Str_indexOfAtUntil(const char* str, char c, Str_LenType num, char end);
+char* Str_indexOfAtFix(const char* str, char c, Str_LenType num, Str_LenType len);
+
+char* Str_reverse(char* str);
+
+char* Str_copyReverse(char* dest, const char* src);
+
+char* Str_substr(char* dest, const char* str, Str_LenType start);
+char* Str_substrFix(char* dest, const char* str, Str_LenType start, Str_LenType len);
+char* Str_substrUntil(char* dest, const char* str, Str_LenType start, char endChar);
+
+char* Str_replace(char* str, const char* word, const char* replacement);
+int Str_replaceAll(char* str, const char* word, const char* replacement);
+
+const char** Str_sort(const char** strs, Str_LenType len);
+const char** Str_quickSort(const char** strs, Str_LenType len);
+const char** Str_sortReverse(const char** strs, Str_LenType len);
+const char** Str_quickSortReverse(const char** strs, Str_LenType len);
+
+Str_LenType Str_split(const char* src, char separator, char* strs, Str_LenType rowLen, Str_LenType len);
+Str_LenType Str_splitPtr(char* src, char separator, char** strs, Str_LenType len, uint8_t setNull);
+char* Str_splitToken(char* src, char separator, char** ptr, uint8_t setNull);
+
+Str_LenType Str_posOf(const char* str, char c);
+Str_LenType Str_lastPosOf(const char* str, char c);
+
+Str_LenType Str_posOfStr(const char* str, const char* word);
+
+Str_LenType Str_multiCompare(const char** strs, Str_LenType len, const char* str);
+Str_LenType Str_multiCompareSorted(const char** strs, Str_LenType len, const char* str);
+
+const char* Str_findStrs(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result);
+const char* Str_findStrsSorted(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result);
+
+const char* Str_findStrsFix(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result, Str_LenType srcLen);
+const char* Str_findStrsSortedFix(const char* src, const char** strs, Str_LenType len, Str_MultiResult* result, Str_LenType srcLen);
+
+Str_LenType Str_parseNum(Str_Num num, Str_Radix base, Str_LenType minLen, char* str);
+Str_LenType Str_parseUNum(Str_UNum num, Str_Radix base, Str_LenType minLen, char* str);
+
+Str_LenType Str_parseString(const char* string, char* str);
+Str_LenType Str_fromString(char* str);
+
+Str_Result Str_convertNum(const char* str, Str_Num* num, Str_Radix base);
+Str_Result Str_convertUNum(const char* str, Str_UNum* num, Str_Radix base);
+Str_Result Str_convertNumFix(const char* str, Str_Num* num, Str_Radix base, Str_LenType len);
+Str_Result Str_convertUNumFix(const char* str, Str_UNum* num, Str_Radix base, Str_LenType len);
+
+char* Str_convertString(const char* str, char* string);
+char* Str_convertStringFix(const char* str, char* string, Str_LenType len);
+
+#if STR_ENABLE_LONG_NUMBER
+
+Str_LenType Str_parseLong(Str_Long num, Str_Radix base, Str_LenType minLen, char* str);
+Str_LenType Str_parseULong(Str_ULong num, Str_Radix base, Str_LenType minLen, char* str);
+
+Str_Result Str_convertLong(const char* str, Str_Long* num, Str_Radix base);
+Str_Result Str_convertULong(const char* str, Str_ULong* num, Str_Radix base);
+Str_Result Str_convertLongFix(const char* str, Str_Long* num, Str_Radix base, Str_LenType len);
+Str_Result Str_convertULongFix(const char* str, Str_ULong* num, Str_Radix base, Str_LenType len);
+
+#endif // STR_ENABLE_LONG_NUMBER
+
+Str_LenType Str_parseFloat(float num, char* str);
+Str_LenType Str_parseFloatFix(float num, char* str, Str_LenType decimalLen);
+
+Str_Result Str_convertFloat(const char* str, float* num);
+Str_Result Str_convertFloatFix(const char* str, float* num, Str_LenType len);
+
+#if STR_ENABLE_DOUBLE
+
+Str_LenType Str_parseDouble(double num, char* str);
+Str_LenType Str_parseDoubleFix(double num, char* str, Str_LenType decimalLen);
+
+Str_Result Str_convertDouble(const char* str, double* num);
+Str_Result Str_convertDoubleFix(const char* str, double* num, Str_LenType len);
+
+#endif // STR_ENABLE_DOUBLE
+
+Str_Result Str_getNum(const char* str, int* num, const char** numPos);
+Str_Result Str_getUNum(const char* str, unsigned int* num, const char** numPos);
+Str_Result Str_getFloat(const char* str, float* num, const char** numPos);
+
+Str_Result Str_getToken(const char* str, char separator, Str_LenType index, char* token);
+Str_Result Str_getTokenFix(const char* str, char separator, Str_LenType index, char* token, Str_LenType len);
+
+/**
+ * Sorting Functions
+ **/
+
+#define Mem_castItem(TYPE, ITEM) ((TYPE*) ITEM)
+
+typedef Mem_CmpResult (*Mem_CompareFn) (const void* itemA, const void* itemB, Mem_LenType itemLen);
+typedef void (*Mem_SwapFn) (void* itemA, void* itemB, Mem_LenType itemLen);
+
+void* Mem_sort(void* items, Mem_LenType len, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap);
+void* Mem_quickSort(void* items, Mem_LenType len, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap);
+
+Mem_LenType Mem_partition(void* items, Mem_LenType low, Mem_LenType high, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap);
+void* Mem_quickSortBlock(void* items, Mem_LenType low, Mem_LenType high, Mem_LenType itemLen, Mem_CompareFn cmp, Mem_SwapFn swap);
+
+Mem_LenType Mem_linearSearch(const void* items, Mem_LenType len, Mem_LenType itemLen, const void* item, Mem_CompareFn cmp);
+Mem_LenType Mem_binarySearch(const void* items, Mem_LenType len, Mem_LenType itemLen, const void* item, Mem_CompareFn cmp);
+
+typedef Str_CmpResult (*Str_CompareFn) (const char* itemA, const char* ItemB);
+
+void Str_swap(const char** itemA, const char** itemB);
+Str_LenType Str_partition(const char** items, Str_LenType low, Str_LenType high, Str_CompareFn cmp);
+const char** Str_quickSortBlock(const char** items, Mem_LenType low, Mem_LenType high, Str_CompareFn cmp);
+
+const char** Str_selectionSortBlock(const char** items, Mem_LenType len, Str_CompareFn cmp);
+
+Str_LenType Str_linearSearch(const char** strs, Str_LenType len, const char* str, Str_CompareFn cmp);
+Str_LenType Str_binarySearch(const char** strs, Str_LenType len, const char* str, Str_CompareFn cmp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif // _STR_UTILS_H_
+
+
diff --git a/Examples/StreamOverSocket/Stream/InputStream.c b/Examples/StreamOverSocket/Stream/InputStream.c
new file mode 100644
index 0000000..7eb4f0c
--- /dev/null
+++ b/Examples/StreamOverSocket/Stream/InputStream.c
@@ -0,0 +1,187 @@
+#include "InputStream.h"
+#include
+
+/**
+ * @brief Initialize InputStream
+ *
+ * @param stream InputStream to initialize
+ * @param receiveFn Function to receive data
+ * @param buff Buffer to hold data
+ * @param size Size of buffer
+ */
+void IStream_init(IStream* stream, IStream_ReceiveFn receiveFn, uint8_t* buff, Stream_LenType size) {
+ Stream_init(&stream->Buffer, buff, size);
+ stream->receive = receiveFn;
+#if ISTREAM_ARGS
+ stream->Args = (void*) 0;
+#endif
+#if ISTREAM_CHECK_RECEIVE
+ stream->checkReceive = (IStream_CheckReceiveFn) 0;
+#endif
+ stream->IncomingBytes = 0;
+}
+/**
+ * @brief Deinitialize InputStream
+ *
+ * @param stream InputStream to deinitialize
+ */
+void IStream_deinit(IStream* stream) {
+ memset(stream, 0, sizeof(IStream));
+}
+
+/**
+ * @brief call in interrupt or RxCplt callback for Async Receive
+ *
+ * @param stream
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result IStream_handle(IStream* stream, Stream_LenType len) {
+ Stream_Result res;
+
+ if (!stream->Buffer.InReceive) {
+ return Stream_NoReceive;
+ }
+
+ if (stream->IncomingBytes < len) {
+ len = stream->IncomingBytes;
+ }
+
+ stream->Buffer.InReceive = 0;
+ if ((res = Stream_moveWritePos(&stream->Buffer, len)) != Stream_Ok) {
+ return res;
+ }
+
+ return IStream_receive(stream);
+}
+/**
+ * @brief call receive function for Async read
+ *
+ * @param stream
+ * @return Stream_Result
+ */
+Stream_Result IStream_receive(IStream* stream) {
+ if (!stream->Buffer.InReceive) {
+ Stream_LenType len = Stream_directSpace(&stream->Buffer);
+ stream->IncomingBytes = len;
+ if (len > 0) {
+ if (stream->receive) {
+ stream->Buffer.InReceive = 1;
+ return stream->receive(stream, IStream_getDataPtr(stream), len);
+ }
+ else {
+ return Stream_NoReceiveFn;
+ }
+ }
+ else {
+ return Stream_NoSpace;
+ }
+ }
+ else {
+ return Stream_InReceive;
+ }
+}
+/**
+ * @brief blocking receive for 1 byte
+ *
+ * @param stream
+ * @param val
+ * @return Stream_Result
+ */
+Stream_Result IStream_receiveByte(IStream* stream, uint8_t val) {
+ *IStream_getDataPtr(stream) = val;
+ return Stream_moveWritePos(&stream->Buffer, 1);
+
+}
+/**
+ * @brief blocking receive for n bytes
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result IStream_receiveBytes(IStream* stream, uint8_t* val, Stream_LenType len) {
+ return Stream_writeBytes(&stream->Buffer, val, len);
+}
+#if ISTREAM_ARGS
+/**
+ * @brief set args for IStream
+ *
+ * @param stream
+ * @param args
+ */
+void IStream_setArgs(IStream* stream, void* args) {
+ stream->Args = args;
+}
+/**
+ * @brief get args form IStream
+ *
+ * @param stream
+ * @return void*
+ */
+void* IStream_getArgs(IStream* stream) {
+ return stream->Args;
+}
+#endif // ISTREAM_ARGS
+/**
+ * @brief return available bytes in buffer to read
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType IStream_available(IStream* stream) {
+#if ISTREAM_CHECK_RECEIVE
+ if (stream->checkReceive) {
+ Stream_LenType len = stream->checkReceive(stream);
+ if (len > 0) {
+ if (stream->IncomingBytes < len) {
+ len = stream->IncomingBytes;
+ }
+ Stream_moveWritePos(&stream->Buffer, len);
+ stream->IncomingBytes -= len;
+ if (stream->Buffer.WPos == 0) {
+ IStream_receive(stream);
+ }
+ }
+ }
+#endif // ISTREAM_CHECK_RECEIVE
+ // now get available bytes len
+ return Stream_available(&stream->Buffer);
+}
+#if ISTREAM_CHECK_RECEIVE
+/**
+ * @brief set check receive function
+ *
+ * @param stream
+ * @param fn
+ */
+void IStream_setCheckReceive(IStream* stream, IStream_CheckReceiveFn fn) {
+ stream->checkReceive = fn;
+}
+#endif // ISTREAM_CHECK_RECEIVE
+/**
+ * @brief return number of bytes that in receive
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType IStream_incomingBytes(IStream* stream) {
+ return stream->IncomingBytes;
+}
+#if ISTREAM_LOCK
+/**
+ * @brief lock input stream for fixed write
+ *
+ * @param stream
+ * @param lock
+ * @return Stream_Result
+ */
+Stream_Result IStream_lock(IStream* stream, IStream* lock, Stream_LenType len) {
+ Stream_Result res;
+ if ((res = Stream_lockRead(&stream->Buffer, &lock->Buffer, len)) == Stream_Ok) {
+ memcpy(&lock->receive, &stream->receive, sizeof(IStream) - sizeof(Stream));
+ }
+ return res;
+}
+#endif // ISTREAM_LOCK
diff --git a/Examples/StreamOverSocket/Stream/InputStream.h b/Examples/StreamOverSocket/Stream/InputStream.h
new file mode 100644
index 0000000..9d8274a
--- /dev/null
+++ b/Examples/StreamOverSocket/Stream/InputStream.h
@@ -0,0 +1,308 @@
+/**
+ * @file InputStream.h
+ * @author Ali Mirghasemi (ali.mirghasemi1376@gamil.com)
+ * @brief this library implement input stream over stream buffer
+ * @version 0.4
+ * @date 2021-09-01
+ *
+ * @copyright Copyright (c) 2021
+ *
+ */
+#ifndef _INPUT_STREAM_H_
+#define _INPUT_STREAM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ISTREAM_VER_MAJOR 0
+#define ISTREAM_VER_MINOR 5
+#define ISTREAM_VER_FIX 0
+
+#include "StreamBuffer.h"
+
+/************************************************************************/
+/* Configuration */
+/************************************************************************/
+
+/**
+ * @brief enable user argument in OStream
+ */
+#define ISTREAM_ARGS 1
+/**
+ * @brief enable checkTransmit function
+ */
+#define ISTREAM_CHECK_RECEIVE 1
+/**
+ * @brief enable lock read feature
+ */
+#define ISTREAM_LOCK STREAM_READ_LOCK
+
+
+/************************************************************************/
+
+/**
+ * @brief show stream version in string format
+ */
+#define ISTREAM_VER_STR _STREAM_VER_STR(ISTREAM_VER_MAJOR, ISTREAM_VER_MINOR, ISTREAM_VER_FIX)
+/**
+ * @brief show stream version in integer format, ex: 0.2.0 -> 200
+ */
+#define ISTREAM_VER ((ISTREAM_VER_MAJOR * 10000UL) + (ISTREAM_VER_MINOR * 100UL) + (ISTREAM_VER_FIX))
+
+/* Pre-defined variables */
+struct __IStream;
+typedef struct __IStream IStream;
+/**
+ * @brief receive function, OStream_space
+ * @param stream IStream
+ * @param buff uint8_t*
+ * @param len Stream_LenType
+ * @return Stream_Result
+ */
+typedef Stream_Result (*IStream_ReceiveFn)(IStream* stream, uint8_t* buff, Stream_LenType len);
+/**
+ * @brief check how many bytes received, this functions allows to check
+ * how many bytes received in available function, it's good to work with DMA
+ * @param stream IStream
+ * @return Stream_LenType
+ */
+typedef Stream_LenType (*IStream_CheckReceiveFn)(IStream* stream);
+
+/**
+ * @brief hold InputStream properties
+ */
+struct __IStream {
+ Stream Buffer; /**< hold stream buffer */
+ IStream_ReceiveFn receive; /**< receive function */
+#if ISTREAM_ARGS
+ void* Args; /**< hold user defined arguments */
+#endif
+#if ISTREAM_CHECK_RECEIVE
+ IStream_CheckReceiveFn checkReceive; /**< check receive function */
+#endif
+ Stream_LenType IncomingBytes; /**< hold how many bytes are coming */
+};
+
+
+void IStream_init(IStream* stream, IStream_ReceiveFn receiveFn, uint8_t* buff, Stream_LenType size);
+void IStream_deinit(IStream* stream);
+
+
+/* Input Bytes of IStream */
+Stream_Result IStream_handle(IStream* stream, Stream_LenType len);
+Stream_Result IStream_receive(IStream* stream);
+Stream_Result IStream_receiveByte(IStream* stream, uint8_t val);
+Stream_Result IStream_receiveBytes(IStream* stream, uint8_t* val, Stream_LenType len);
+
+#define IStream_availableUncheck(STREAM) Stream_available(&(STREAM)->Buffer)
+Stream_LenType IStream_available(IStream* stream);
+
+Stream_LenType IStream_incomingBytes(IStream* stream);
+
+#define IStream_inReceive(STREAM) Stream_inReceive(&(STREAM)->Buffer)
+
+#if ISTREAM_ARGS
+ void IStream_setArgs(IStream* stream, void* args);
+ void* IStream_getArgs(IStream* stream);
+#endif // ISTREAM_ARGS
+
+#if ISTREAM_CHECK_RECEIVE
+ void IStream_setCheckReceive(IStream* stream, IStream_CheckReceiveFn fn);
+#endif // ISTREAM_CHECK_RECEIVE
+
+#if ISTREAM_LOCK
+ Stream_Result IStream_lock(IStream* stream, IStream* lock, Stream_LenType len);
+ #define IStream_unlock(STREAM, LOCK) Stream_unlockRead(&(STREAM)->Buffer, &(LOCK)->Buffer);
+ #define IStream_unlockIgnore(STREAM) Stream_unlockReadIgnore(&(STREAM)->Buffer)
+ #define IStream_lockLen(STREAM, LOCK) Stream_lockReadLen(&(STREAM)->Buffer, &(LOCK)->Buffer)
+#endif // ISTREAM_LOCK
+
+#define IStream_getDataPtr(STREAM) Stream_getWritePtr(&((STREAM)->Buffer))
+
+#define IStream_clear(STREAM) Stream_clear(&((STREAM)->Buffer))
+#define IStream_reset(STREAM) Stream_reset(&((STREAM)->Buffer))
+#define IStream_resetIO(STREAM) Stream_resetIO(&((STREAM)->Buffer))
+
+#if STREAM_BYTE_ORDER
+ #define IStream_getSystemByteOrder() Stream_getSystemByteOrder()
+ #define IStream_setByteOrder(STREAM, ORDER) Stream_setByteOrder(&((STREAM)->Buffer), ORDER)
+ #define IStream_getByteOrder(STREAM) Stream_getByteOrder(&((STREAM)->Buffer))
+#endif
+
+#if STREAM_READ_LIMIT
+ #define IStream_setLimit(STREAM, LEN) Stream_setReadLimit(&((STREAM)->Buffer), (LEN))
+ #define IStream_getLimit(STREAM) Stream_getReadLimit(&((STREAM)->Buffer))
+ #define IStream_isLimited(STREAM) Stream_isReadLimited(&((STREAM)->Buffer))
+#endif
+
+#if STREAM_CURSOR
+ #define IStream_getCursor(STREAM, CUR) Stream_getCursor(&((STREAM)->Buffer), (CUR))
+ #define IStream_len(STREAM, CUR) Stream_getReadLen(&((STREAM)->Buffer), (CUR))
+#endif
+
+#define IStream_ignore(STREAM, LEN) Stream_moveReadPos(&((STREAM)->Buffer), (LEN))
+
+/* Read function same as Stream read functions */
+#define IStream_read(STREAM) Stream_read(&((STREAM)->Buffer))
+#define IStream_readBytes(STREAM, VAL, LEN) Stream_readBytes(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_readBytesReverse(STREAM, VAL, LEN) Stream_readBytesReverse(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_readStream(IN, OUT, LEN) Stream_readStream(&((IN)->Buffer), &((OUT)->Buffer), (LEN))
+#define IStream_readChar(STREAM) Stream_readChar(&((STREAM)->Buffer))
+#define IStream_readUInt8(STREAM) Stream_readUInt8(&((STREAM)->Buffer))
+#define IStream_readInt8(STREAM) Stream_readInt8(&((STREAM)->Buffer))
+#define IStream_readUInt16(STREAM) Stream_readUInt16(&((STREAM)->Buffer))
+#define IStream_readInt16(STREAM) Stream_readInt16(&((STREAM)->Buffer))
+#define IStream_readUInt32(STREAM) Stream_readUInt32(&((STREAM)->Buffer))
+#define IStream_readInt32(STREAM) Stream_readInt32(&((STREAM)->Buffer))
+#define IStream_readFloat(STREAM) Stream_readFloat(&((STREAM)->Buffer))
+
+#if STREAM_UINT64
+ #define IStream_readUInt64(STREAM) Stream_readUInt64(&((STREAM)->Buffer))
+ #define IStream_readInt64(STREAM) Stream_readInt64(&((STREAM)->Buffer))
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ #define IStream_readDouble(STREAM) Stream_readDouble(&((STREAM)->Buffer))
+#endif // STREAM_DOUBLE
+
+#define IStream_readCharArray(STREAM, VAL, LEN) Stream_readCharArray(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_readUInt8Array(STREAM, VAL, LEN) Stream_readUInt8Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_readInt8Array(STREAM, VAL, LEN) Stream_readInt8Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_readUInt16Array(STREAM, VAL, LEN) Stream_readUInt16Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_readInt16Array(STREAM, VAL, LEN) Stream_readInt16Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_readUInt32Array(STREAM, VAL, LEN) Stream_readUInt32Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_readInt32Array(STREAM, VAL, LEN) Stream_readInt32Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_readFloatArray(STREAM, VAL, LEN) Stream_readFloatArray(&((STREAM)->Buffer), (VAL), (LEN))
+
+#if STREAM_UINT64
+ #define IStream_readUInt64Array(STREAM,VAL,LEN) Stream_readUInt64Array(&((STREAM)->Buffer), (VAL), (LEN))
+ #define IStream_readInt64Array(STREAM,VAL,LEN) Stream_readInt64Array(&((STREAM)->Buffer), (VAL), (LEN))
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ #define IStream_readDoubleArray(STREAM,VAL,LEN) Stream_readDoubleArray(&((STREAM)->Buffer), (VAL), (LEN))
+#endif // STREAM_DOUBLE
+
+#define IStream_getBytes(STREAM, VAL, LEN) Stream_getBytes((STREAM), (VAL), (LEN))
+#define IStream_getBytesReverse(STREAM, VAL, LEN) Stream_getBytesReverse(&((STREAM)->Buffer), (VAL), (LEN));
+#define IStream_getChar(STREAM) Stream_getChar(&((STREAM)->Buffer))
+#define IStream_getUInt8(STREAM) Stream_getUInt8(&((STREAM)->Buffer))
+#define IStream_getInt8(STREAM) Stream_getInt8(&((STREAM)->Buffer))
+#define IStream_getUInt16(STREAM) Stream_getUInt16(&((STREAM)->Buffer))
+#define IStream_getInt16(STREAM) Stream_getInt16(&((STREAM)->Buffer))
+#define IStream_getUInt32(STREAM) Stream_getUInt32(&((STREAM)->Buffer))
+#define IStream_getInt32(STREAM) Stream_getInt32(&((STREAM)->Buffer))
+#define IStream_getFloat(STREAM) Stream_getFloat(&((STREAM)->Buffer))
+
+#if STREAM_UINT64
+ #define IStream_getUInt64(STREAM) Stream_getUInt64(&((STREAM)->Buffer))
+ #define IStream_getInt64(STREAM) Stream_getInt64(&((STREAM)->Buffer))
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ #define IStream_getDouble(STREAM) Stream_getDouble(&((STREAM)->Buffer))
+#endif // STREAM_DOUBLE
+
+#define IStream_getCharArray(STREAM, VAL, LEN) Stream_getCharArray(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_getUInt8Array(STREAM, VAL, LEN) Stream_getUInt8Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_getInt8Array(STREAM, VAL, LEN) Stream_getInt8Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_getUInt16Array(STREAM, VAL, LEN) Stream_getUInt16Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_getInt16Array(STREAM, VAL, LEN) Stream_getInt16Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_getUInt32Array(STREAM, VAL, LEN) Stream_getUInt32Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_getInt32Array(STREAM, VAL, LEN) Stream_getInt32Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_getFloatArray(STREAM, VAL, LEN) Stream_getFloatArray(&((STREAM)->Buffer), (VAL), (LEN))
+
+#if STREAM_UINT64
+ #define IStream_getUInt64Array(STREAM,VAL,LEN) Stream_getUInt64Array(&((STREAM)->Buffer), (VAL), (LEN))
+ #define IStream_getInt64Array(STREAM,VAL,LEN) Stream_getInt64Array(&((STREAM)->Buffer), (VAL), (LEN))
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ #define IStream_getDoubleArray(STREAM,VAL,LEN) Stream_getDoubleArray(&((STREAM)->Buffer), (VAL), (LEN))
+#endif // STREAM_DOUBLE
+
+#define IStream_getBytesAt(STREAM, IXD, VAL, LEN) Stream_getBytesAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#define IStream_getBytesReverseAt(STREAM, IDX, VAL, LEN) Stream_getBytesReverseAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN));
+#define IStream_getCharAt(STREAM, IDX) Stream_getCharAt(&((STREAM)->Buffer), (IDX))
+#define IStream_getUInt8At(STREAM, IDX) Stream_getUInt8At(&((STREAM)->Buffer), (IDX))
+#define IStream_getInt8At(STREAM, IDX) Stream_getInt8At(&((STREAM)->Buffer), (IDX))
+#define IStream_getUInt16At(STREAM, IDX) Stream_getUInt16At(&((STREAM)->Buffer), (IDX))
+#define IStream_getInt16At(STREAM, IDX) Stream_getInt16At(&((STREAM)->Buffer), (IDX))
+#define IStream_getUInt32At(STREAM, IDX) Stream_getUInt32At(&((STREAM)->Buffer), (IDX))
+#define IStream_getInt32At(STREAM, IDX) Stream_getInt32At(&((STREAM)->Buffer), (IDX))
+#define IStream_getFloatAt(STREAM, IDX) Stream_getFloatAt(&((STREAM)->Buffer), (IDX))
+
+#if STREAM_UINT64
+ #define IStream_getUInt64At(STREAM) Stream_getUInt64At(&((STREAM)->Buffer), (IDX))
+ #define IStream_getInt64At(STREAM) Stream_getInt64At(&((STREAM)->Buffer), (IDX))
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ #define IStream_getDoubleAt(STREAM) Stream_getDoubleAt(&((STREAM)->Buffer), (IDX))
+#endif // STREAM_DOUBLE
+
+#define IStream_getCharArrayAt(STREAM, IDX, VAL, LEN) Stream_getCharArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#define IStream_getUInt8ArrayAt(STREAM, IDX, VAL, LEN) Stream_getUInt8ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#define IStream_getInt8ArrayAt(STREAM, IDX, VAL, LEN) Stream_getInt8ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#define IStream_getUInt16ArrayAt(STREAM, IDX, VAL, LEN) Stream_getUInt16ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#define IStream_getInt16ArrayAt(STREAM, IDX, VAL, LEN) Stream_getInt16ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#define IStream_getUInt32ArrayAt(STREAM, IDX, VAL, LEN) Stream_getUInt32ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#define IStream_getInt32ArrayAt(STREAM, IDX, VAL, LEN) Stream_getInt32ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#define IStream_getFloatArrayAt(STREAM, IDX, VAL, LEN) Stream_getFloatArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+
+#if STREAM_UINT64
+ #define IStream_getUInt64ArrayAt(STREAM,IDX,VAL,LEN) Stream_getUInt64ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+ #define IStream_getInt64ArrayAt(STREAM,IDX,VAL,LEN) Stream_getInt64ArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ #define IStream_getDoubleArrayAt(STREAM,IDX,VAL,LEN) Stream_getDoubleArrayAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+#endif // STREAM_DOUBLE
+
+#if STREAM_FIND_FUNCTIONS
+ #define IStream_findByte(STREAM, VAL) Stream_findByte(&((STREAM)->Buffer), (VAL))
+ #define IStream_findByteAt(STREAM, IDX, VAL) Stream_findByteAt(&((STREAM)->Buffer))
+ #define IStream_findPattern(STREAM, PAT, PAT_LEN) Stream_findPattern(&((STREAM)->Buffer), (PAT), (PAT_LEN))
+ #define IStream_findPatternAt(STREAM, IDX, PAT, PAT_LEN) Stream_findPatternAt(&((STREAM)->Buffer), (IDX), (PAT), (PAT_LEN))
+ #define IStream_readBytesUntil(STREAM, END, VAL, LEN) Stream_readBytesUntil(&((STREAM)->Buffer), (END), (VAL), (LEN))
+ #define IStream_readBytesUntilAt(STREAM, IDX, END, VAL, LEN) Stream_readBytesUntil(&((STREAM)->Buffer), (IDX), (END), (VAL), (LEN))
+ #define IStream_readBytesUntilPattern(STREAM, PAT, PAT_LEN, VAL, LEN) Stream_readBytesUntilPattern(&((STREAM)->Buffer), (PAT), (PAT_LEN), (VAL), (LEN))
+ #define IStream_readBytesUntilPatternAt(STREAM, IDX, PAT, PAT_LEN, VAL, LEN) Stream_readBytesUntilPatternAt(&((STREAM)->Buffer), (IDX), (PAT), (PAT_LEN), (VAL), (LEN))
+
+ #define IStream_findUInt8(STREAM, VAL) Stream_findUInt8(&((STREAM)->Buffer), (VAL))
+ #define IStream_findInt8(STREAM, VAL) Stream_findInt8(&((STREAM)->Buffer), (VAL))
+ #define IStream_findUInt16(STREAM, VAL) Stream_findUInt16(&((STREAM)->Buffer), (VAL))
+ #define IStream_findInt16(STREAM, VAL) Stream_findInt16(&((STREAM)->Buffer), (VAL))
+ #define IStream_findUInt32(STREAM, VAL) Stream_findUInt32(&((STREAM)->Buffer), (VAL))
+ #define IStream_findInt32(STREAM, VAL) Stream_findInt32(&((STREAM)->Buffer), (VAL))
+#if STREAM_UINT64
+ #define IStream_findUInt64(STREAM, VAL) Stream_findUInt64(&((STREAM)->Buffer), (VAL))
+ #define IStream_findInt64(STREAM, VAL) Stream_findInt64(&((STREAM)->Buffer), (VAL))
+#endif
+ #define IStream_findFloat(STREAM, VAL) Stream_findFloat(&((STREAM)->Buffer), (VAL))
+#if STREAM_DOUBLE
+ #define IStream_findDouble(STREAM, VAL) Stream_findDouble(&((STREAM)->Buffer), (VAL))
+#endif
+
+#if STREAM_FIND_AT_FUNCTIONS
+ #define IStream_findUInt8At(STREAM, IDX, VAL) Stream_findUInt8(&((STREAM)->Buffer), (IDX), (VAL))
+ #define IStream_findInt8At(STREAM, IDX, VAL) Stream_findInt8(&((STREAM)->Buffer), (IDX), (VAL))
+ #define IStream_findUInt16At(STREAM, IDX, VAL) Stream_findUInt16(&((STREAM)->Buffer), (IDX), (VAL))
+ #define IStream_findInt16At(STREAM, IDX, VAL) Stream_findInt16(&((STREAM)->Buffer), (IDX), (VAL))
+ #define IStream_findUInt32At(STREAM, IDX, VAL) Stream_findUInt32(&((STREAM)->Buffer), (IDX), (VAL))
+ #define IStream_findInt32At(STREAM, IDX, VAL) Stream_findInt32(&((STREAM)->Buffer), (IDX), (VAL))
+#if STREAM_UINT64
+ #define IStream_findUInt64At(STREAM, IDX, VAL) Stream_findUInt64(&((STREAM)->Buffer), (IDX), (VAL))
+ #define IStream_findInt64At(STREAM, IDX, VAL) Stream_findInt64(&((STREAM)->Buffer), (IDX), (VAL))
+#endif
+ #define IStream_findFloatAt(STREAM, IDX, VAL) Stream_findFloat(&((STREAM)->Buffer), (IDX), (VAL))
+#if STREAM_DOUBLE
+ #define IStream_findDoubleAt(STREAM, IDX, VAL) Stream_findDouble(&((STREAM)->Buffer), (IDX), (VAL))
+#endif
+#endif // STREAM_FIND_AT_FUNCTIONS
+
+#endif // STREAM_FIND_FUNCTIONS
+
+#define IStream_compare(STREAM, VAL, LEN) Stream_compareAt(&((STREAM)->Buffer), (VAL), (LEN))
+#define IStream_compareAt(STREAM, IDX, VAL, LEN) Stream_compareAt(&((STREAM)->Buffer), (IDX), (VAL), (LEN))
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _INPUT_STREAM_H_ */
diff --git a/Examples/StreamOverSocket/Stream/OutputStream.c b/Examples/StreamOverSocket/Stream/OutputStream.c
new file mode 100644
index 0000000..4b0e9bc
--- /dev/null
+++ b/Examples/StreamOverSocket/Stream/OutputStream.c
@@ -0,0 +1,256 @@
+#include "OutputStream.h"
+#include
+
+/**
+ * @brief Initialize OutputStream
+ *
+ * @param stream OutputStream to initialize
+ * @param transmitFn Function to transmit data
+ * @param buff Buffer to hold data
+ * @param size Size of buffer
+ */
+void OStream_init(OStream* stream, OStream_TransmitFn transmitFn, uint8_t* buff, Stream_LenType size) {
+ Stream_init(&stream->Buffer, buff, size);
+ stream->Buffer.FlushMode = OSTREAM_FLUSH_MODE;
+ stream->transmit = transmitFn;
+#if OSTREAM_ARGS
+ stream->Args = (void*) 0;
+#endif
+#if OSTREAM_CHECK_TRANSMIT
+ stream->checkTransmit = (OStream_CheckTransmitFn) 0;
+#endif
+ stream->OutgoingBytes = 0;
+}
+/**
+ * @brief Deinitialize OutputStream
+ *
+ * @param stream OutputStream to deinitialize
+ */
+void OStream_deinit(OStream* stream) {
+ memset(stream, 0, sizeof(OStream));
+}
+
+
+/**
+ * @brief call it in interrupt or TxCplt for Async Transmit
+ *
+ * @param stream
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result OStream_handle(OStream* stream, Stream_LenType len) {
+ Stream_Result res;
+ if (!stream->Buffer.InTransmit) {
+ return Stream_NoTransmit;
+ }
+
+ if (stream->OutgoingBytes < len) {
+ len = stream->OutgoingBytes;
+ }
+
+ stream->Buffer.InTransmit = 0;
+ if ((res = Stream_moveReadPos(&stream->Buffer, len)) != Stream_Ok) {
+ return res;
+ }
+
+#if OSTREAM_FLUSH_CALLBACK
+ if (stream->flushCallback && OStream_pendingBytes(stream) == 0) {
+ stream->flushCallback(stream);
+ }
+#endif
+
+ return stream->Buffer.FlushMode != Stream_FlushMode_Single ?
+ OStream_flush(stream) :
+ Stream_Ok;
+}
+/**
+ * @brief start sending bytes and flush stream in Async Transmit
+ *
+ * @param stream
+ * @return Stream_Result
+ */
+Stream_Result OStream_flush(OStream* stream) {
+ if (!stream->Buffer.InTransmit) {
+ Stream_LenType len = Stream_directAvailable(&stream->Buffer);
+ stream->OutgoingBytes = len;
+ if (len > 0) {
+ if (stream->transmit) {
+ stream->Buffer.InTransmit = 1;
+ return stream->transmit(stream, OStream_getDataPtr(stream), len);
+ }
+ else {
+ return Stream_NoTransmitFn;
+ }
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+ }
+ else {
+ return Stream_InTransmit;
+ }
+}
+/**
+ * @brief flush and wait for transmit all pending bytes
+ *
+ * @param stream
+ * @return Stream_Result
+ */
+Stream_Result OStream_flushBlocking(OStream* stream) {
+ Stream_Result res;
+
+ while (OStream_pendingBytes(stream) == 0) {
+ if ((res = OStream_flush(stream)) != Stream_Ok) {
+ break;
+ }
+ }
+
+ return res;
+}
+/**
+ * @brief blocking transmit 1 byte just call transmit function no need handle function
+ *
+ * @param stream
+ * @return Stream_Result
+ */
+Stream_Result OStream_transmitByte(OStream* stream) {
+ Stream_LenType len = Stream_directAvailable(&stream->Buffer);
+ if (len > 0) {
+ if (stream->transmit) {
+ stream->transmit(stream, OStream_getDataPtr(stream), 1);
+ return Stream_moveReadPos(&stream->Buffer, 1);
+ }
+ else {
+ return Stream_NoTransmitFn;
+ }
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief blocking transmit n byte just call transmit function no need handle function
+ *
+ * @param stream
+ * @return Stream_Result
+ */
+Stream_Result OStream_transmitBytes(OStream* stream, Stream_LenType len) {
+ Stream_LenType dirLen = OStream_pendingBytes(stream);
+ Stream_Result res;
+ if (dirLen < len) {
+ len = dirLen;
+ }
+ while (len > 0) {
+ dirLen = Stream_directAvailable(&stream->Buffer);
+ if (dirLen > 0) {
+ if (stream->transmit) {
+ if (dirLen > len) {
+ dirLen = len;
+ }
+ stream->transmit(stream, OStream_getDataPtr(stream), dirLen);
+ if ((res = Stream_moveReadPos(&stream->Buffer, 1)) != Stream_Ok) {
+ return res;
+ }
+ len -= dirLen;
+ }
+ else {
+ return Stream_NoTransmitFn;
+ }
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+ }
+ return Stream_Ok;
+}
+#if OSTREAM_ARGS
+/**
+ * @brief set args for OStream
+ *
+ * @param stream
+ * @param args
+ */
+void OStream_setArgs(OStream* stream, void* args) {
+ stream->Args = args;
+}
+/**
+ * @brief get args for OStream
+ *
+ * @param stream
+ * @return void*
+ */
+void* OStream_getArgs(OStream* stream) {
+ return stream->Args;
+}
+#endif // OSTREAM_ARGS
+#if OSTREAM_CHECK_TRANSMIT
+/**
+ * @brief set check transmit function for OStream
+ *
+ * @param stream
+ * @param checkTransmit
+ */
+void OStream_setCheckTransmit(OStream* stream, OStream_CheckTransmitFn fn) {
+ stream->checkTransmit = fn;
+}
+#endif // OSTREAM_CHECK_TRANSMIT
+#if OSTREAM_FLUSH_CALLBACK
+/**
+ * @brief set flush callback function
+ *
+ * @param stream
+ * @param fn
+ */
+void OStream_setFlushCallback(OStream* stream, OStream_FlushCallbackFn fn) {
+ stream->flushCallback = fn;
+}
+#endif
+/**
+ * @brief return available space for write in bytes
+ *
+ * @param stream
+ * @return OStream_CheckTransmitFn
+ */
+Stream_LenType OStream_space(OStream* stream) {
+#if OSTREAM_CHECK_TRANSMIT
+ if (stream->checkTransmit) {
+ Stream_LenType len = stream->checkTransmit(stream);
+ if (len > 0) {
+ if (stream->OutgoingBytes < len) {
+ len = stream->OutgoingBytes;
+ }
+ Stream_moveReadPos(&stream->Buffer, len);
+ stream->OutgoingBytes -= len;
+ if (stream->Buffer.RPos == 0) {
+ OStream_flush(stream);
+ }
+ }
+ }
+#endif // OSTREAM_CHECK_TRANSMIT
+ return Stream_space(&stream->Buffer);
+}
+/**
+ * @brief return number of bytes that are in transmit
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType OStream_outgoingBytes(OStream* stream) {
+ return stream->OutgoingBytes;
+}
+#if OSTREAM_LOCK
+/**
+ * @brief lock output stream for fixed write
+ *
+ * @param stream
+ * @param lock
+ * @return Stream_Result
+ */
+Stream_Result OStream_lock(OStream* stream, OStream* lock, Stream_LenType len) {
+ Stream_Result res;
+ if ((res = Stream_lockWrite(&stream->Buffer, &lock->Buffer, len)) == Stream_Ok) {
+ memcpy(&lock->transmit, &stream->transmit, sizeof(OStream) - sizeof(Stream));
+ }
+ return res;
+}
+#endif // OSTREAM_LOCK
diff --git a/Examples/StreamOverSocket/Stream/OutputStream.h b/Examples/StreamOverSocket/Stream/OutputStream.h
new file mode 100644
index 0000000..30e0f71
--- /dev/null
+++ b/Examples/StreamOverSocket/Stream/OutputStream.h
@@ -0,0 +1,218 @@
+/**
+ * @file OutputStream.h
+ * @author Ali Mirghasemi (ali.mirghasemi1376@gmail.com)
+ * @brief this library implement output stream over stream buffer
+ * @version 0.4
+ * @date 2021-09-01
+ *
+ * @copyright Copyright (c) 2021
+ *
+ */
+#ifndef _OUTPUT_STREAM_H_
+#define _OUTPUT_STREAM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OSTREAM_VER_MAJOR 0
+#define OSTREAM_VER_MINOR 5
+#define OSTREAM_VER_FIX 0
+
+#include "StreamBuffer.h"
+
+/************************************************************************/
+/* Configuration */
+/************************************************************************/
+
+/**
+ * @brief enable user argument in OStream
+ */
+#define OSTREAM_ARGS 1
+/**
+ * @brief enable checkTransmit function
+ */
+#define OSTREAM_CHECK_TRANSMIT 1
+/**
+ * @brief enable lock write feature
+ */
+#define OSTREAM_LOCK STREAM_WRITE_LOCK
+/**
+ * @brief set default flush mode
+ * Stream_FlushMode_Single: flush only pending bytes before call flush function
+ * Stream_FlushMode_Continue: after flush complete if there is any pending bytes transmit pending bytes again
+ */
+#define OSTREAM_FLUSH_MODE Stream_FlushMode_Continue
+/**
+ * @brief enable flush complete callback
+ */
+#define OSTREAM_FLUSH_CALLBACK 1
+
+/************************************************************************/
+
+/**
+ * @brief show stream version in string format
+ */
+#define OSTREAM_VER_STR _STREAM_VER_STR(OSTREAM_VER_MAJOR, OSTREAM_VER_MINOR, OSTREAM_VER_FIX)
+/**
+ * @brief show stream version in integer format, ex: 0.2.0 -> 200
+ */
+#define OSTREAM_VER ((OSTREAM_VER_MAJOR * 10000UL) + (OSTREAM_VER_MINOR * 100UL) + (OSTREAM_VER_FIX))
+
+/* Pre-defined variables */
+struct __OStream;
+typedef struct __OStream OStream;
+
+/**
+ * @brief transmit function, this function allow stream to work with hardware
+ * @param stream OStream
+ * @param buff uint8_t*
+ * @param len Stream_LenType
+ */
+typedef Stream_Result (*OStream_TransmitFn)(OStream* stream, uint8_t* buff, Stream_LenType len);
+/**
+ * @brief check how many bytes transmitted, this functions allow stream to check
+ * how many bytes transmitted over hardware, it's good for work with DMA
+ * @param stream OStream
+ * @return Stream_LenType return how many bytes transmitted
+ */
+typedef Stream_LenType (*OStream_CheckTransmitFn)(OStream* stream);
+/**
+ * @brief flush callback, call after flush completed
+ *
+ */
+typedef void (*OStream_FlushCallbackFn)(OStream* stream);
+
+/**
+ * @brief hold OutputStream properties
+ */
+struct __OStream {
+ Stream Buffer; /**< stream buffer */
+ OStream_TransmitFn transmit; /**< transmit function */
+#if OSTREAM_ARGS
+ void* Args; /**< user argument */
+#endif
+#if OSTREAM_CHECK_TRANSMIT
+ OStream_CheckTransmitFn checkTransmit; /**< check transmit function */
+#endif
+#if OSTREAM_FLUSH_CALLBACK
+ OStream_FlushCallbackFn flushCallback; /**< flush callback */
+#endif
+ Stream_LenType OutgoingBytes; /**< outgoing bytes */
+};
+
+
+void OStream_init(OStream* stream, OStream_TransmitFn transmitFn, uint8_t* buff, Stream_LenType size);
+void OStream_deinit(OStream* stream);
+
+
+/* Output Bytes of OStream */
+Stream_Result OStream_handle(OStream* stream, Stream_LenType len);
+Stream_Result OStream_flush(OStream* stream);
+Stream_Result OStream_flushBlocking(OStream* stream);
+Stream_Result OStream_transmitByte(OStream* stream);
+Stream_Result OStream_transmitBytes(OStream* stream, Stream_LenType len);
+
+#define OStream_spaceUncheck(STREAM) Stream_space(&(STREAM)->Buffer)
+Stream_LenType OStream_space(OStream* stream);
+
+Stream_LenType OStream_outgoingBytes(OStream* stream);
+
+#define OStream_setFlushMode(STREAM, MODE) Stream_setFlushMode(&(STREAM)->Buffer, (MODE))
+
+#define OStream_inTransmit(STREAM) Stream_inTransmit(&(STREAM)->Buffer)
+
+#if OSTREAM_ARGS
+ void OStream_setArgs(OStream* stream, void* args);
+ void* OStream_getArgs(OStream* stream);
+#endif // OSTREAM_ARGS
+
+#if OSTREAM_CHECK_TRANSMIT
+ void OStream_setCheckTransmit(OStream* stream, OStream_CheckTransmitFn fn);
+#endif // OSTREAM_CHECK_TRANSMIT
+
+#if OSTREAM_FLUSH_CALLBACK
+ void OStream_setFlushCallback(OStream* stream, OStream_FlushCallbackFn fn);
+#endif
+
+#if OSTREAM_LOCK
+ Stream_Result OStream_lock(OStream* stream, OStream* lock, Stream_LenType len);
+ #define OStream_unlock(STREAM, LOCK) Stream_unlockWrite(&(STREAM)->Buffer, &(LOCK)->Buffer);
+ #define OStream_unlockIgnore(STREAM) Stream_unlockWriteIgnore(&(STREAM)->Buffer)
+ #define OStream_lockLen(STREAM, LOCK) Stream_lockWriteLen(&(STREAM)->Buffer, &(LOCK)->Buffer)
+#endif // OSTREAM_LOCK
+
+/**
+ * @brief return number of bytes waiting for transmit
+ */
+#define OStream_pendingBytes(STREAM) Stream_available(&((STREAM)->Buffer))
+
+#define OStream_getDataPtr(STREAM) Stream_getReadPtr(&((STREAM)->Buffer))
+
+#define OStream_clear(STREAM) Stream_clear(&((STREAM)->Buffer))
+#define OStream_reset(STREAM) Stream_reset(&((STREAM)->Buffer))
+#define OStream_resetIO(STREAM) Stream_resetIO(&((STREAM)->Buffer))
+
+#if STREAM_BYTE_ORDER
+ #define OStream_getSystemByteOrder() Stream_getSystemByteOrder()
+ #define OStream_setByteOrder(STREAM, ORDER) Stream_setByteOrder(&((STREAM)->Buffer), ORDER)
+ #define OStream_getByteOrder(STREAM) Stream_getByteOrder(&((STREAM)->Buffer))
+#endif
+
+#if STREAM_WRITE_LIMIT
+ #define OStream_setLimit(STREAM, LEN) Stream_setWriteLimit(&((STREAM)->Buffer), (LEN))
+ #define OStream_getLimit(STREAM) Stream_getWriteLimit(&((STREAM)->Buffer))
+ #define OStream_isLimited(STREAM) Stream_isWriteLimited(&((STREAM)->Buffer))
+#endif
+
+#if STREAM_CURSOR
+ #define OStream_getCursor(STREAM, CUR) Stream_getCursor(&((STREAM)->Buffer), (CUR))
+ #define OStream_len(STREAM, CUR) Stream_getWriteLen(&((STREAM)->Buffer), (CUR))
+#endif
+
+#define OStream_ignore(STREAM, LEN) Stream_moveWritePos(&((STREAM)->Buffer), (LEN))
+
+#define OStream_writeBytes(STREAM, VAL, LEN) Stream_writeBytes(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeBytesReverse(STREAM, VAL, LEN) Stream_writeBytesReverse(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeStream(OUT, IN, LEN) Stream_writeStream(&((OUT)->Buffer), &((IN)->Buffer), (LEN))
+#define OStream_writePadding(STREAM, VAL, LEN) Stream_writePadding(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeChar(STREAM, VAL) Stream_writeChar(&((STREAM)->Buffer), (VAL))
+#define OStream_writeStr(STREAM, VAL) Stream_writeStr(&((STREAM)->Buffer), (VAL))
+#define OStream_writeUInt8(STREAM, VAL) Stream_writeUInt8(&((STREAM)->Buffer), (VAL))
+#define OStream_writeInt8(STREAM, VAL) Stream_writeInt8(&((STREAM)->Buffer), (VAL))
+#define OStream_writeUInt16(STREAM, VAL) Stream_writeUInt16(&((STREAM)->Buffer), (VAL))
+#define OStream_writeInt16(STREAM, VAL) Stream_writeInt16(&((STREAM)->Buffer), (VAL))
+#define OStream_writeUInt32(STREAM, VAL) Stream_writeUInt32(&((STREAM)->Buffer), (VAL))
+#define OStream_writeInt32(STREAM, VAL) Stream_writeInt32(&((STREAM)->Buffer), (VAL))
+#define OStream_writeFloat(STREAM, VAL) Stream_writeFloat(&((STREAM)->Buffer), (VAL))
+#if STREAM_UINT64
+#define OStream_writeUInt64(STREAM, VAL) Stream_writeUInt64(&((STREAM)->Buffer), (VAL))
+#define OStream_writeInt64(STREAM, VAL) Stream_writeInt64(&((STREAM)->Buffer), (VAL))
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+#define OStream_writeDouble(STREAM, VAL) Stream_writeDouble(&((STREAM)->Buffer), (VAL))
+#endif // STREAM_DOUBLE
+
+#define OStream_writeCharArray(STREAM, VAL, LEN) Stream_writeCharArray(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeUInt8Array(STREAM, VAL, LEN) Stream_writeUInt8Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeInt8Array(STREAM, VAL, LEN) Stream_writeInt8Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeUInt16Array(STREAM, VAL, LEN) Stream_writeUInt16Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeInt16Array(STREAM, VAL, LEN) Stream_writeInt16Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeUInt32Array(STREAM, VAL, LEN) Stream_writeUInt32Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeInt32Array(STREAM, VAL, LEN) Stream_writeInt32Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeFloatArray(STREAM, VAL, LEN) Stream_writeFloatArray(&((STREAM)->Buffer), (VAL), (LEN))
+#if STREAM_UINT64
+#define OStream_writeUInt64Array(STREAM, VAL, LEN) Stream_writeUInt64Array(&((STREAM)->Buffer), (VAL), (LEN))
+#define OStream_writeInt64Array(STREAM, VAL, LEN) Stream_writeInt64Array(&((STREAM)->Buffer), (VAL), (LEN))
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+#define OStream_writeDoubleArray(STREAM, VAL, LEN) Stream_writeDoubleArray(&((STREAM)->Buffer), (VAL), (LEN))
+#endif // STREAM_DOUBLE
+
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // _OUTPUT_STREAM_H_
diff --git a/Examples/StreamOverSocket/Stream/StreamBuffer.c b/Examples/StreamOverSocket/Stream/StreamBuffer.c
new file mode 100644
index 0000000..b9dfcfb
--- /dev/null
+++ b/Examples/StreamOverSocket/Stream/StreamBuffer.c
@@ -0,0 +1,2437 @@
+#include "StreamBuffer.h"
+#include
+
+/* Memory IO Macros */
+#if STREAM_MEM_IO == STREAM_MEM_IO_DEFAULT
+ #define __memCopy(S, DEST, SRC, LEN) STREAM_MEM_COPY((DEST), (SRC), (LEN))
+ #define __memCopyReverse(S, DEST, SRC, LEN) STREAM_MEM_COPY_REVERSE((DEST), (SRC), (LEN))
+ #define __memSet(S, SRC, VAL, LEN) STREAM_MEM_SET((SRC), (VAL), (LEN))
+ #define __memReverse(S, SRC, LEN) STREAM_MEM_REVERSE((SRC), (LEN))
+#elif STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM
+ #define __memCopy(S, DEST, SRC, LEN) (S)->Mem.copy((DEST), (SRC), (LEN))
+ #define __memCopyReverse(S, DEST, SRC, LEN) (S)->Mem.copyReverse((DEST), (SRC), (LEN))
+ #define __memSet(S, SRC, VAL, LEN) (S)->Mem.set((SRC), (VAL), (LEN))
+ #define __memReverse(S, SRC, LEN) (S)->Mem.reverse((SRC), (LEN))
+#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER
+ #define __memCopy(S, DEST, SRC, LEN) (S)->Mem->copy((DEST), (SRC), (LEN))
+ #define __memCopyReverse(S, DEST, SRC, LEN) (S)->Mem->copyReverse((DEST), (SRC), (LEN))
+ #define __memSet(S, SRC, VAL, LEN) (S)->Mem->set((SRC), (VAL), (LEN))
+ #define __memReverse(S, SRC, LEN) (S)->Mem->reverse((SRC), (LEN))
+#else
+ #error "STREAM_MEM_IO is invalid!"
+#endif
+
+#if STREAM_BYTE_ORDER
+/* private typedef */
+typedef Stream_Result (*Stream_WriteBytesFn)(Stream* stream, uint8_t* val, Stream_LenType len);
+typedef Stream_Result (*Stream_ReadBytesFn)(Stream* stream, uint8_t* val, Stream_LenType len);
+typedef Stream_Result (*Stream_GetBytesFn)(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len);
+/* private variables */
+static const Stream_WriteBytesFn writeBytes[2] = {
+ Stream_writeBytes,
+ Stream_writeBytesReverse,
+};
+static const Stream_ReadBytesFn readBytes[2] = {
+ Stream_readBytes,
+ Stream_readBytesReverse,
+};
+#if STREAM_GET_AT_FUNCTIONS
+static const Stream_GetBytesFn getBytesAt[2] = {
+ Stream_getBytesAt,
+ Stream_getBytesReverseAt,
+};
+#endif
+
+ #define __writeBytes(STREAM, VAL, LEN) writeBytes[STREAM->OrderFn]((STREAM), (VAL), (LEN))
+ #define __readBytes(STREAM, VAL, LEN) readBytes[STREAM->OrderFn]((STREAM), (VAL), (LEN))
+ #define __getBytesAt(STREAM, INDEX, VAL, LEN) getBytesAt[STREAM->OrderFn]((STREAM), (INDEX), (VAL), (LEN))
+
+ #define __checkReverse(STREAM, VAL) if (STREAM->OrderFn) {__memReverse((STREAM), &VAL, sizeof(VAL));}
+
+#else
+ #define __writeBytes(STREAM, VAL, LEN) Stream_writeBytes((STREAM), (VAL), (LEN))
+ #define __readBytes(STREAM, VAL, LEN) Stream_readBytes((STREAM), (VAL), (LEN))
+ #define __getBytesAt(STREAM, INDEX, VAL, LEN) Stream_getBytesAt((STREAM), (INDEX), (VAL), (LEN))
+
+ #define __checkReverse(STREAM, VAL)
+#endif // STREAM_BYTE_ORDER
+
+/* private function */
+static void memrcpy(void* dest, const void* src, int len);
+static void memreverse(void* arr, int len);
+
+/* Stream MemIO default driver*/
+#if STREAM_MEM_IO == STREAM_MEM_IO_DRIVER
+static const Stream_MemIO STREAM_DEFAULT_DRIVER = {
+ (Stream_MemCopyFn) STREAM_MEM_COPY,
+ (Stream_MemCopyReverseFn) STREAM_MEM_COPY_REVERSE,
+ (Stream_MemSetFn) STREAM_MEM_SET,
+ (Stream_MemReverseFn) STREAM_MEM_REVERSE,
+};
+#endif
+
+/**
+ * @brief initialize stream
+ *
+ * @param stream address of stream struct
+ * @param buffer address of byte buffer
+ * @param size size of buffer
+ */
+void Stream_init(Stream* stream, uint8_t* buffer, Stream_LenType size) {
+ stream->Data = buffer;
+ stream->Size = size;
+ stream->Overflow = 0;
+ stream->InReceive = 0;
+ stream->InTransmit = 0;
+#if STREAM_BYTE_ORDER
+ stream->Order = Stream_getSystemByteOrder();
+ stream->OrderFn = 0;
+#endif // STREAM_BYTE_ORDER
+ stream->RPos = 0;
+ stream->WPos = 0;
+#if STREAM_WRITE_LIMIT
+ stream->WriteLimit = STREAM_NO_LIMIT;
+#endif // STREAM_WRITE_LIMIT
+#if STREAM_READ_LIMIT
+ stream->ReadLimit = STREAM_NO_LIMIT;
+#endif // STREAM_READ_LIMIT
+#if STREAM_WRITE_LOCK
+ stream->WriteLocked = 0;
+#endif // STREAM_WRITE_LOCK
+#if STREAM_READ_LOCK
+ stream->ReadLocked = 0;
+#endif // STREAM_READ_LOCK
+#if STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM
+ Stream_setMemIO(
+ stream,
+ (Stream_MemCopyFn) STREAM_MEM_COPY,
+ (Stream_MemCopyReverseFn) STREAM_MEM_COPY_REVERSE,
+ (Stream_MemSetFn) STREAM_MEM_SET,
+ (Stream_MemReverseFn) STREAM_MEM_REVERSE
+ );
+#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER
+ Stream_setMemIO(stream, &STREAM_DEFAULT_DRIVER);
+#endif
+}
+/**
+ * @brief initialize stream with a buffer that already have data in it
+ *
+ * @param stream
+ * @param buffer
+ * @param size
+ */
+void Stream_fromBuff(Stream* stream, uint8_t* buffer, Stream_LenType size) {
+ Stream_init(stream, buffer, size);
+ stream->WPos = size;
+}
+/**
+ * @brief reset stream struct into default values
+ *
+ * @param stream address of stream
+ */
+void Stream_deinit(Stream* stream) {
+ __memSet(stream, stream, 0, sizeof(Stream));
+}
+#if STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM
+/**
+ * @brief Set custom memory io functions
+ * if input is null use default functions
+ *
+ * @param stream
+ * @param copy
+ * @param copyReverse
+ * @param set
+ * @param reverse
+ */
+void Stream_setMemIO(
+ Stream* stream,
+ Stream_MemCopyFn copy,
+ Stream_MemCopyReverseFn copyReverse,
+ Stream_MemSetFn set,
+ Stream_MemReverseFn reverse
+) {
+ stream->Mem.copy = copy ? copy : (Stream_MemCopyFn) STREAM_MEM_COPY;
+ stream->Mem.copyReverse = copyReverse ? copyReverse : (Stream_MemCopyReverseFn) STREAM_MEM_COPY_REVERSE;
+ stream->Mem.set = set ? set : (Stream_MemSetFn) STREAM_MEM_SET;
+ stream->Mem.reverse = reverse ? reverse : (Stream_MemReverseFn) STREAM_MEM_REVERSE;
+}
+#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER
+/**
+ * @brief Set memory io driver
+ * if input is null use default driver. all function must exists
+ *
+ * @param stream
+ * @param mem
+ */
+void Stream_setMemIO(Stream* stream, const Stream_MemIO* mem) {
+ stream->Mem = mem ? mem : &STREAM_DEFAULT_DRIVER;
+}
+#endif
+
+/**
+ * @brief return available bytes to read
+ *
+ * @param stream
+ * @return Stream_LenType available bytes
+ */
+Stream_LenType Stream_availableReal(Stream* stream) {
+ return stream->Size * stream->Overflow + stream->WPos - stream->RPos;
+}
+/**
+ * @brief return buffer space for write bytes
+ *
+ * @param stream
+ * @return Stream_LenType space for write
+ */
+Stream_LenType Stream_spaceReal(Stream* stream) {
+ return stream->Size * !stream->Overflow + stream->RPos - stream->WPos;
+}
+/**
+ * @brief check stream is empty
+ * no bytes available to read
+ * @param stream
+ * @return uint8_t 0 -> Not Empty, 1-> it's empty
+ */
+uint8_t Stream_isEmpty(Stream* stream) {
+ return stream->RPos == stream->WPos && !stream->Overflow;
+}
+/**
+ * @brief check stream it's full
+ * no bytes can write
+ *
+ * @param stream
+ * @return uint8_t 0 -> Not Full, 1-> it's Full
+ */
+uint8_t Stream_isFull(Stream* stream) {
+ return stream->RPos == stream->WPos && stream->Overflow;
+}
+/**
+ * @brief reset stream
+ *
+ * @param stream
+ */
+void Stream_reset(Stream* stream) {
+ stream->RPos = 0;
+ stream->WPos = 0;
+ stream->Overflow = 0;
+}
+/**
+ * @brief reset stream and ignore receive and transmit operations
+ *
+ * @param stream
+ */
+void Stream_resetIO(Stream* stream) {
+ stream->RPos = 0;
+ stream->WPos = 0;
+ stream->Overflow = 0;
+ stream->InReceive = 0;
+ stream->InTransmit = 0;
+}
+/**
+ * @brief clear buffer and reset stream
+ *
+ * @param stream
+ */
+void Stream_clear(Stream* stream) {
+ Stream_reset(stream);
+ __memSet(stream, stream->Data, 0, stream->Size);
+}
+/**
+ * @brief
+ *
+ * @param stream
+ * @param mode
+ */
+void Stream_setFlushMode(Stream* stream, Stream_FlushMode mode) {
+ stream->FlushMode = mode;
+}
+/**
+ * @brief return in receive flag
+ *
+ * @param stream
+ * @return uint8_t
+ */
+uint8_t Stream_inReceive(Stream* stream) {
+ return stream->InReceive;
+}
+/**
+ * @brief return in transmit flag
+ *
+ * @param stream
+ * @return uint8_t
+ */
+uint8_t Stream_inTransmit(Stream* stream) {
+ return stream->InTransmit;
+}
+/**
+ * @brief return Write Pos
+ *
+ * @param stream
+ * @return Stream_LenType it's between 0 ~ Size
+ */
+Stream_LenType Stream_getWritePos(Stream* stream) {
+ return stream->WPos;
+}
+/**
+ * @brief return Read Pos
+ *
+ * @param stream
+ * @return Stream_LenType it's between 0 ~ Size
+ */
+Stream_LenType Stream_getReadPos(Stream* stream) {
+ return stream->RPos;
+}
+/**
+ * @brief return number of bytes that it's in row in the ram
+ * use for transmit function in OStream
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_directAvailable(Stream* stream) {
+ return stream->Overflow ? stream->Size - stream->RPos :
+ stream->WPos - stream->RPos;
+}
+/**
+ * @brief return number of bytes it's in row in the ram
+ * use for receive function in IStream
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_directSpace(Stream* stream) {
+ return stream->Overflow ? stream->RPos - stream->WPos :
+ stream->Size - stream->WPos;
+}
+/**
+ * @brief return number of bytes that it's in row in the ram
+ * use for transmit function in OStream
+ * offset is RPos
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_directAvailableAt(Stream* stream, Stream_LenType index) {
+ Stream_LenType len = Stream_availableReal(stream);
+ Stream_LenType dirLen = Stream_directAvailable(stream);
+ if (len == dirLen) {
+ return len - index;
+ }
+ else {
+ return dirLen > index ? dirLen - index :
+ stream->WPos - (index - dirLen);
+ }
+}
+/**
+ * @brief return number of bytes it's in row in the ram
+ * use for receive function in IStream
+ * offset is WPos
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_directSpaceAt(Stream* stream, Stream_LenType index) {
+ Stream_LenType len = Stream_spaceReal(stream);
+ Stream_LenType dirLen = Stream_directSpace(stream);
+ if (len == dirLen) {
+ return len - index;
+ }
+ else {
+ return dirLen > index ? dirLen - index :
+ stream->RPos - (index - dirLen);
+ }
+}
+/**
+ * @brief get ptr to start of WPos in ram
+ *
+ * @param stream
+ * @return uint8_t*
+ */
+uint8_t* Stream_getWritePtr(Stream* stream) {
+ return &stream->Data[stream->WPos];
+}
+/**
+ * @brief get ptr to start of RPos in ram
+ *
+ * @param stream
+ * @return uint8_t*
+ */
+uint8_t* Stream_getReadPtr(Stream* stream) {
+ return &stream->Data[stream->RPos];
+}
+uint8_t* Stream_getWritePtrAt(Stream* stream, Stream_LenType index) {
+ index += stream->WPos;
+
+ if (index >= stream->Size) {
+ index %= stream->Size;
+ }
+
+ return &stream->Data[index];
+}
+uint8_t* Stream_getReadPtrAt(Stream* stream, Stream_LenType index) {
+ index += stream->RPos;
+
+ if (index >= stream->Size) {
+ index %= stream->Size;
+ }
+
+ return &stream->Data[index];
+}
+/**
+ * @brief set buffer for stream and reset stream
+ *
+ * @param stream
+ */
+void Stream_setBuffer(Stream* stream, uint8_t* data, Stream_LenType size) {
+ Stream_init(stream, data, size);
+}
+/**
+ * @brief return byte buffer
+ *
+ * @param stream
+ * @return uint8_t*
+ */
+uint8_t* Stream_getBuffer(Stream* stream) {
+ return stream->Data;
+}
+/**
+ * @brief return size of stream buffer
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_getBufferSize(Stream* stream) {
+ return stream->Size;
+}
+/**
+ * @brief can use for ignore bytes, and move WPos index
+ *
+ * @param stream
+ * @param steps
+ * @return Stream_Result
+ */
+Stream_Result Stream_moveWritePos(Stream* stream, Stream_LenType steps) {
+ if (Stream_space(stream) < steps) {
+ return Stream_NoSpace;
+ }
+
+ stream->WPos += steps;
+ if (stream->WPos >= stream->Size) {
+ stream->WPos %= stream->Size;
+ stream->Overflow = 1;
+ }
+
+ return Stream_Ok;
+}
+/**
+ * @brief can use for ignore bytes, and move RPos index
+ *
+ * @param stream
+ * @param steps
+ * @return Stream_Result
+ */
+Stream_Result Stream_moveReadPos(Stream* stream, Stream_LenType steps) {
+ if (Stream_available(stream) < steps) {
+ return Stream_NoAvailable;
+ }
+
+ stream->RPos += steps;
+ if (stream->RPos >= stream->Size) {
+ stream->RPos %= stream->Size;
+ stream->Overflow = 0;
+ }
+
+ return Stream_Ok;
+}
+/**
+ * @brief flip space size for write
+ *
+ * @param stream
+ * @param len
+ */
+void Stream_flipWrite(Stream* stream, Stream_LenType len) {
+ stream->RPos = stream->WPos + len;
+ if (stream->RPos >= stream->Size) {
+ stream->RPos %= stream->Size;
+ stream->Overflow = 0;
+ }
+ else {
+ stream->Overflow = 1;
+ }
+}
+/**
+ * @brief flip available size for read
+ *
+ * @param stream
+ * @param len
+ */
+void Stream_flipRead(Stream* stream, Stream_LenType len) {
+ stream->WPos = stream->RPos + len;
+ if (stream->WPos >= stream->Size) {
+ stream->WPos %= stream->Size;
+ stream->Overflow = 1;
+ }
+ else {
+ stream->Overflow = 0;
+ }
+}
+#if STREAM_BYTE_ORDER
+
+/**
+ * @brief determine platform byte order
+ *
+ * @return ByteOrder
+ */
+ByteOrder Stream_getSystemByteOrder(void) {
+#if STREAM_BYTE_ORDER_SYS_STATIC
+ static ByteOrder sysByteOrder = ByteOrder_Reserved;
+ if (sysByteOrder == ByteOrder_Reserved) {
+ const uint8_t arr[2] = {0xAA, 0xBB};
+ const uint16_t val = 0xAABB;
+ sysByteOrder = (ByteOrder) (memcmp(arr, (uint8_t*) &val, sizeof(val)) == 0);
+ }
+ return sysByteOrder;
+#else
+ const uint8_t arr[2] = {0xAA, 0xBB};
+ const uint16_t val = 0xAABB;
+ return (ByteOrder) (memcmp(arr, (uint8_t*) &val, sizeof(val)) == 0);
+#endif
+}
+/**
+ * @brief set stream r/w byte order
+ *
+ * @param stream
+ * @param order
+ */
+void Stream_setByteOrder(Stream* stream, ByteOrder order) {
+ ByteOrder osOrder = Stream_getSystemByteOrder();
+ stream->Order = order;
+ stream->OrderFn = osOrder != order;
+}
+/**
+ * @brief return stream byte order
+ *
+ * @param stream
+ * @return ByteOrder
+ */
+ByteOrder Stream_getByteOrder(Stream* stream) {
+ return (ByteOrder) stream->Order;
+}
+#endif
+#if STREAM_WRITE_LIMIT
+/**
+ * @brief set limit for write operations, you can't set limit greater than space
+ *
+ * @param stream
+ * @param len
+ */
+void Stream_setWriteLimit(Stream* stream, Stream_LenType len) {
+ Stream_LenType space = Stream_spaceReal(stream);
+ if (space < len) {
+ len = space;
+ }
+ stream->WriteLimit = len;
+}
+/**
+ * @brief return write operation is limited or not
+ *
+ * @param stream
+ * @return uint8_t true means limited
+ */
+uint8_t Stream_isWriteLimited(Stream* stream) {
+ return stream->WriteLimit >= 0;
+}
+/**
+ * @brief return space available for write bytes respect to write limit
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_spaceLimit(Stream* stream) {
+ return stream->WriteLimit >= 0 ? stream->WriteLimit : Stream_spaceReal(stream);
+}
+Stream_LenType Stream_getWriteLimit(Stream* stream) {
+ return stream->WriteLimit;
+}
+#endif // STREAM_WRITE_LIMIT
+#if STREAM_READ_LIMIT
+/**
+ * @brief set limit for read operations, you can't set limit greater than available
+ *
+ * @param stream
+ * @param len
+ */
+void Stream_setReadLimit(Stream* stream, Stream_LenType len) {
+ Stream_LenType available = Stream_availableReal(stream);
+ if (available < len) {
+ len = available;
+ }
+ stream->ReadLimit = len;
+}
+/**
+ * @brief return read operations is limited or not
+ *
+ * @param stream
+ * @return uint8_t true means it's limited
+ */
+uint8_t Stream_isReadLimited(Stream* stream) {
+ return stream->ReadLimit >= 0;
+}
+/**
+ * @brief retruna available bytes for read respect to read limit
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_availableLimit(Stream* stream) {
+ return stream->ReadLimit >= 0 ? stream->ReadLimit : Stream_availableReal(stream);
+}
+/**
+ * @brief return read limit
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_getReadLimit(Stream* stream) {
+ return stream->ReadLimit;
+}
+#endif // STREAM_READ_LIMIT
+#if STREAM_CURSOR
+/**
+ * @brief fill cursor object based on given stream
+ *
+ * @param stream
+ * @param cursor
+ */
+void Stream_getCursor(Stream* stream, Stream_Cursor* cursor) {
+ cursor->WPos = stream->WPos;
+ cursor->RPos = stream->RPos;
+}
+/**
+ * @brief return read len from cursor pos
+ *
+ * @param stream
+ * @param cursor
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_getReadLen(Stream* stream, Stream_Cursor* cursor) {
+ return cursor->RPos >= stream->RPos ? cursor->RPos - stream->RPos :
+ (stream->Size - cursor->RPos) + stream->RPos;
+}
+/**
+ * @brief return write len from cursor pos
+ *
+ * @param stream
+ * @param cursor
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_getWriteLen(Stream* stream, Stream_Cursor* cursor) {
+ return cursor->WPos >= stream->WPos ? cursor->WPos - stream->WPos :
+ (stream->Size - cursor->WPos) + stream->WPos;
+}
+#endif // STREAM_CURSOR
+/**
+ * @brief write byte array into stream
+ *
+ * @param stream
+ * @param val byte array
+ * @param len len of array
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeBytes(Stream* stream, uint8_t* val, Stream_LenType len) {
+#if STREAM_CHECK_ZERO_LEN
+ if (len == 0) {
+ return Stream_ZeroLen;
+ }
+#endif
+ if (Stream_space(stream) < len) {
+ return Stream_NoSpace;
+ }
+#if STREAM_WRITE_LIMIT
+ if (Stream_isWriteLimited(stream)) {
+ stream->WriteLimit -= len;
+ }
+#endif
+
+ if (stream->WPos + len >= stream->Size) {
+ Stream_LenType tmpLen;
+
+ tmpLen = stream->Size - stream->WPos;
+ len -= tmpLen;
+ __memCopy(stream, &stream->Data[stream->WPos], val, tmpLen);
+ val += tmpLen;
+ // move WPos
+ stream->WPos = 0;
+ stream->Overflow = 1;
+ }
+ if (len > 0) {
+ __memCopy(stream, &stream->Data[stream->WPos], val, len);
+ // move WPos
+ stream->WPos += len;
+ }
+
+ return Stream_Ok;
+}
+/**
+ * @brief write array into stream in reverse order
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len) {
+#if STREAM_CHECK_ZERO_LEN
+ if (len == 0) {
+ return Stream_ZeroLen;
+ }
+#endif
+ if (Stream_space(stream) < len) {
+ return Stream_NoSpace;
+ }
+#if STREAM_WRITE_LIMIT
+ if (Stream_isWriteLimited(stream)) {
+ stream->WriteLimit -= len;
+ }
+#endif
+
+ if (stream->WPos + len >= stream->Size) {
+ Stream_LenType tmpLen;
+
+ tmpLen = stream->Size - stream->WPos;
+ len -= tmpLen;
+ __memCopyReverse(stream, &stream->Data[stream->WPos], val + len, tmpLen);
+ // move WPos
+ stream->WPos = 0;
+ stream->Overflow = 1;
+ }
+ if (len > 0) {
+ __memCopyReverse(stream, &stream->Data[stream->WPos], val, len);
+ // move WPos
+ stream->WPos += len;
+ }
+
+ return Stream_Ok;
+}
+/**
+ * @brief directly read from a stream and write to another
+ *
+ * @param stream
+ * @param in
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeStream(Stream* out, Stream* in, Stream_LenType len) {
+ // check available space for write
+#if STREAM_CHECK_ZERO_LEN
+ if (len == 0) {
+ return Stream_ZeroLen;
+ }
+#endif
+ if (Stream_space(out) < len) {
+ return Stream_NoSpace;
+ }
+ // check available bytes for read
+ if (Stream_available(in) < len) {
+ return Stream_NoAvailable;
+ }
+#if STREAM_WRITE_LIMIT
+ if (Stream_isWriteLimited(out)) {
+ out->WriteLimit -= len;
+ }
+#endif
+
+ if (out->WPos + len >= out->Size) {
+ Stream_LenType tmpLen;
+ tmpLen = out->Size - out->WPos;
+ len -= tmpLen;
+ Stream_readBytes(in, &out->Data[out->WPos], tmpLen);
+ // move WPos
+ out->WPos = 0;
+ out->Overflow = 1;
+ }
+ if (len > 0) {
+ Stream_readBytes(in, &out->Data[out->WPos], len);
+ // move WPos
+ out->WPos += len;
+ }
+
+ return Stream_Ok;
+
+}
+/**
+ * @brief this function can use for write value multiple time into stream, can use for padding
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writePadding(Stream* stream, uint8_t val, Stream_LenType len) {
+#if STREAM_CHECK_ZERO_LEN
+ if (len == 0) {
+ return Stream_ZeroLen;
+ }
+#endif
+ if (Stream_space(stream) < len) {
+ return Stream_NoSpace;
+ }
+#if STREAM_WRITE_LIMIT
+ if (Stream_isWriteLimited(stream)) {
+ stream->WriteLimit -= len;
+ }
+#endif
+
+ if (stream->WPos + len >= stream->Size) {
+ Stream_LenType tmpLen;
+
+ tmpLen = stream->Size - stream->WPos;
+ len -= tmpLen;
+ __memSet(stream, &stream->Data[stream->WPos], val, tmpLen);
+ val += tmpLen;
+ // move WPos
+ stream->WPos = 0;
+ stream->Overflow = 1;
+ }
+ if (len > 0) {
+ __memSet(stream, &stream->Data[stream->WPos], val, len);
+ // move WPos
+ stream->WPos += len;
+ }
+
+ return Stream_Ok;
+}
+Stream_Result Stream_writeChar(Stream* stream, char val) {
+ return Stream_writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_Result Stream_writeStr(Stream* stream, const char* val) {
+ return Stream_writeBytes(stream, (uint8_t*) val, strlen(val));
+}
+Stream_Result Stream_writeUInt8(Stream* stream, uint8_t val) {
+ return Stream_writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_Result Stream_writeInt8(Stream* stream, int8_t val) {
+ return Stream_writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_Result Stream_writeUInt16(Stream* stream, uint16_t val) {
+ return __writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_Result Stream_writeInt16(Stream* stream, int16_t val) {
+ return __writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_Result Stream_writeUInt32(Stream* stream, uint32_t val) {
+ return __writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_Result Stream_writeInt32(Stream* stream, int32_t val) {
+ return __writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_Result Stream_writeFloat(Stream* stream, float val) {
+ return __writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+#if STREAM_UINT64
+Stream_Result Stream_writeUInt64(Stream* stream, uint64_t val) {
+ return __writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_Result Stream_writeInt64(Stream* stream, int64_t val) {
+ return __writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+Stream_Result Stream_writeDouble(Stream* stream, double val) {
+ return __writeBytes(stream, (uint8_t*) &val, sizeof(val));
+}
+#endif // STREAM_DOUBLE
+
+/**
+ * @brief read one byte from stream if available return value between 0~255, else return -1
+ *
+ * @param stream
+ * @return int16_t
+ */
+int16_t Stream_read(Stream* stream) {
+ if (Stream_available(stream)) {
+ return (int16_t) Stream_readUInt8(stream);
+ }
+ else {
+ return -1;
+ }
+}
+/**
+ * @brief read bytes form stream, if possible
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readBytes(Stream* stream, uint8_t* val, Stream_LenType len) {
+#if STREAM_CHECK_ZERO_LEN
+ if (len == 0) {
+ return Stream_ZeroLen;
+ }
+#endif
+ if (Stream_available(stream) < len) {
+ return Stream_NoAvailable;
+ }
+#if STREAM_READ_LIMIT
+ if (Stream_isReadLimited(stream)) {
+ stream->ReadLimit -= len;
+ }
+#endif
+
+ if (stream->RPos + len >= stream->Size) {
+ Stream_LenType tmpLen;
+
+ tmpLen = stream->Size - stream->RPos;
+ len -= tmpLen;
+ __memCopy(stream, val, &stream->Data[stream->RPos], tmpLen);
+ val += tmpLen;
+ // move RPos
+ stream->RPos = 0;
+ stream->Overflow = 0;
+ }
+ if (len > 0) {
+ __memCopy(stream, val, &stream->Data[stream->RPos], len);
+ // move RPos
+ stream->RPos += len;
+ }
+
+ return Stream_Ok;
+}
+Stream_Result Stream_readBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len) {
+#if STREAM_CHECK_ZERO_LEN
+ if (len == 0) {
+ return Stream_ZeroLen;
+ }
+#endif
+ if (Stream_available(stream) < len) {
+ return Stream_NoAvailable;
+ }
+#if STREAM_READ_LIMIT
+ if (Stream_isReadLimited(stream)) {
+ stream->ReadLimit -= len;
+ }
+#endif
+
+ if (stream->RPos + len >= stream->Size) {
+ Stream_LenType tmpLen;
+
+ tmpLen = stream->Size - stream->RPos;
+ len -= tmpLen;
+ __memCopyReverse(stream, val + len, &stream->Data[stream->RPos], tmpLen);
+ // move RPos
+ stream->RPos = 0;
+ stream->Overflow = 0;
+ }
+ if (len > 0) {
+ __memCopyReverse(stream, val, &stream->Data[stream->RPos], len);
+ // move RPos
+ stream->RPos += len;
+ }
+
+ return Stream_Ok;
+}
+Stream_Result Stream_readStream(Stream* in, Stream* out, Stream_LenType len) {
+#if STREAM_CHECK_ZERO_LEN
+ if (len == 0) {
+ return Stream_ZeroLen;
+ }
+#endif
+ if (Stream_available(in) < len) {
+ return Stream_NoAvailable;
+ }
+ if (Stream_space(out) < len) {
+ return Stream_NoSpace;
+ }
+#if STREAM_READ_LIMIT
+ if (Stream_isReadLimited(in)) {
+ in->ReadLimit -= len;
+ }
+#endif
+
+ if (in->RPos + len >= in->Size) {
+ Stream_LenType tmpLen;
+
+ tmpLen = in->Size - in->RPos;
+ len -= tmpLen;
+ Stream_writeBytes(out, &in->Data[in->RPos], tmpLen);
+ // move RPos
+ in->RPos = 0;
+ in->Overflow = 0;
+ }
+ if (len > 0) {
+ Stream_writeBytes(out, &in->Data[in->RPos], len);
+ // move RPos
+ in->RPos += len;
+ }
+
+ return Stream_Ok;
+}
+char Stream_readChar(Stream* stream) {
+ char val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+uint8_t Stream_readUInt8(Stream* stream) {
+ uint8_t val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+int8_t Stream_readInt8(Stream* stream) {
+ int8_t val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+uint16_t Stream_readUInt16(Stream* stream) {
+ uint16_t val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+int16_t Stream_readInt16(Stream* stream) {
+ int16_t val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+uint32_t Stream_readUInt32(Stream* stream) {
+ uint32_t val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+int32_t Stream_readInt32(Stream* stream) {
+ int32_t val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+float Stream_readFloat(Stream* stream) {
+ float val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+#if STREAM_UINT64
+uint64_t Stream_readUInt64(Stream* stream) {
+ uint64_t val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+int64_t Stream_readInt64(Stream* stream) {
+ int64_t val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+double Stream_readDouble(Stream* stream) {
+ double val = STREAM_READ_DEFAULT_VALUE;
+ __readBytes(stream, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+#endif // STREAM_DOUBLE
+
+#if STREAM_GET_AT_FUNCTIONS && STREAM_GET_FUNCTIONS
+
+Stream_Result Stream_getBytes(Stream* stream, uint8_t* val, Stream_LenType len) {
+ return Stream_getBytesAt(stream, stream->RPos, val, len);
+}
+Stream_Result Stream_getBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len) {
+ return Stream_getBytesAt(stream, stream->RPos, val, len);
+}
+char Stream_getChar(Stream* stream) {
+ return Stream_getCharAt(stream, stream->RPos);
+}
+uint8_t Stream_getUInt8(Stream* stream) {
+ return Stream_getUInt8At(stream, stream->RPos);
+}
+int8_t Stream_getInt8(Stream* stream) {
+ return Stream_getInt8At(stream, stream->RPos);
+}
+uint16_t Stream_getUInt16(Stream* stream) {
+ return Stream_getUInt16At(stream, stream->RPos);
+}
+int16_t Stream_getInt16(Stream* stream) {
+ return Stream_getInt16At(stream, stream->RPos);
+}
+uint32_t Stream_getUInt32(Stream* stream) {
+ return Stream_getUInt32At(stream, stream->RPos);
+}
+int32_t Stream_getInt32(Stream* stream) {
+ return Stream_getInt32At(stream, stream->RPos);
+}
+float Stream_getFloat(Stream* stream) {
+ return Stream_getFloatAt(stream, stream->RPos);
+}
+#if STREAM_UINT64
+uint64_t Stream_getUInt64(Stream* stream) {
+ return Stream_getUInt64At(stream, stream->RPos);
+}
+int64_t Stream_getInt64(Stream* stream) {
+ return Stream_getInt64At(stream, stream->RPos);
+}
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+double Stream_getDouble(Stream* stream) {
+ return Stream_getDoubleAt(stream, stream->RPos);
+}
+#endif // STREAM_DOUBLE
+/**
+ * @brief get array of characters without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getCharArray(Stream* stream, char* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getCharAt(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of uint8_t without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getUInt8At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of int8_t without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getInt8Array(Stream* stream, int8_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getInt8At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of uint16_t without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getUInt16At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of int16_t without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getInt16Array(Stream* stream, int16_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getInt16At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of uint32_t without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getUInt32At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of int32_t without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getInt32Array(Stream* stream, int32_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getInt32At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of float without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getFloatArray(Stream* stream, float* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getFloatAt(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+#if STREAM_UINT64
+/**
+ * @brief get array of uint64_t without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getUInt64At(stream, index);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of int64_t without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getInt64Array(Stream* stream, int64_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getInt64At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+/**
+ * @brief get array of double without change the position of stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getDoubleArray(Stream* stream, double* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ Stream_LenType index = 0;
+ while (len-- > 0) {
+ *val++ = Stream_getDoubleAt(stream, index);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+#endif // STREAM_DOUBLE
+
+#endif // STREAM_GET_FUNCTIONS
+
+#if STREAM_GET_AT_FUNCTIONS
+
+Stream_Result Stream_getBytesAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len) {
+#if STREAM_CHECK_ZERO_LEN
+ if (len == 0) {
+ return Stream_ZeroLen;
+ }
+#endif
+ if (Stream_available(stream) - index < len) {
+ return Stream_NoAvailable;
+ }
+
+ index = (stream->RPos + index) % stream->Size;
+
+ if (index + len >= stream->Size) {
+ Stream_LenType tmpLen;
+
+ tmpLen = stream->Size - index;
+ len -= tmpLen;
+ __memCopy(stream, val, &stream->Data[index], tmpLen);
+ val += tmpLen;
+ index = (index + tmpLen) % stream->Size;
+ }
+
+ __memCopy(stream, val, &stream->Data[index], len);
+
+ return Stream_Ok;
+}
+Stream_Result Stream_getBytesReverseAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len) {
+#if STREAM_CHECK_ZERO_LEN
+ if (len == 0) {
+ return Stream_ZeroLen;
+ }
+#endif
+ if (Stream_available(stream) - index < len) {
+ return Stream_NoAvailable;
+ }
+
+ index = (stream->RPos + index) % stream->Size;
+
+ if (index + len >= stream->Size) {
+ Stream_LenType tmpLen;
+
+ tmpLen = stream->Size - index;
+ len -= tmpLen;
+ __memCopyReverse(stream, val, &stream->Data[index + len], tmpLen);
+ val += tmpLen;
+ index = (index + tmpLen) % stream->Size;
+ }
+
+ __memCopyReverse(stream, val, &stream->Data[index], len);
+
+ return Stream_Ok;
+}
+char Stream_getCharAt(Stream* stream, Stream_LenType index) {
+ char val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+uint8_t Stream_getUInt8At(Stream* stream, Stream_LenType index) {
+ uint8_t val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+int8_t Stream_getInt8At(Stream* stream, Stream_LenType index) {
+ int8_t val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+uint16_t Stream_getUInt16At(Stream* stream, Stream_LenType index) {
+ uint16_t val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+int16_t Stream_getInt16At(Stream* stream, Stream_LenType index) {
+ int16_t val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+uint32_t Stream_getUInt32At(Stream* stream, Stream_LenType index) {
+ uint32_t val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+int32_t Stream_getInt32At(Stream* stream, Stream_LenType index) {
+ int32_t val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+float Stream_getFloatAt(Stream* stream, Stream_LenType index) {
+ float val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+#if STREAM_UINT64
+uint64_t Stream_getUInt64At(Stream* stream, Stream_LenType index) {
+ uint64_t val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+int64_t Stream_getInt64At(Stream* stream, Stream_LenType index) {
+ int64_t val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+double Stream_getDoubleAt(Stream* stream, Stream_LenType index) {
+ double val = STREAM_READ_DEFAULT_VALUE;
+ __getBytesAt(stream, index, (uint8_t*) &val, sizeof(val));
+ return val;
+}
+#endif // STREAM_DOUBLE
+
+/**
+ * @brief get array of string without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getCharArrayAt(Stream* stream, Stream_LenType index, char* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getCharAt(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of uint8_t without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getUInt8ArrayAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getUInt8At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of int8_t without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getInt8ArrayAt(Stream* stream, Stream_LenType index, int8_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getInt8At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of uint16_t without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getUInt16ArrayAt(Stream* stream, Stream_LenType index, uint16_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getUInt16At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of int16_t without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getInt16ArrayAt(Stream* stream, Stream_LenType index, int16_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getInt16At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of uint32_t without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getUInt32ArrayAt(Stream* stream, Stream_LenType index, uint32_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getUInt32At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of int32_t without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getInt32ArrayAt(Stream* stream, Stream_LenType index, int32_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getInt32At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of uint64_t without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getFloatArrayAt(Stream* stream, Stream_LenType index, float* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getFloatAt(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+#if STREAM_UINT64
+/**
+ * @brief get array of uint64_t without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getUInt64ArrayAt(Stream* stream, Stream_LenType index, uint64_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getUInt64At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief get array of int64_t without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getInt64ArrayAt(Stream* stream, Stream_LenType index, int64_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getInt64At(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+/**
+ * @brief get array of double without change the position of stream at given index
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_getDoubleArrayAt(Stream* stream, Stream_LenType index, double* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_getDoubleAt(stream, index++);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+#endif // STREAM_DOUBLE
+
+#endif // STREAM_GET_AT_FUNCTIONS
+/**
+ * @brief write array of characters
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeCharArray(Stream* stream, char* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeChar(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+/**
+ * @brief write array of uint8_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeUInt8(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+/**
+ * @brief write array of int8_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeInt8Array(Stream* stream, int8_t* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeInt8(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+/**
+ * @brief write array of uint16_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeUInt16(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+/**
+ * @brief write array of int16_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeInt16Array(Stream* stream, int16_t* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeInt16(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+/**
+ * @brief write array of uint32_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeUInt32(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+/**
+ * @brief write array of int32_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeInt32Array(Stream* stream, int32_t* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeInt32(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+/**
+ * @brief write array of float
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeFloatArray(Stream* stream, float* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeFloat(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+#if STREAM_UINT64
+/**
+ * @brief write array of uint64_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeUInt64(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+/**
+ * @brief write array of int64_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeInt64Array(Stream* stream, int64_t* val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeInt64(stream, *val++)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+/**
+ * @brief write array of double
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_writeDoubleArray(Stream* stream, double val, Stream_LenType len) {
+ Stream_Result result = Stream_Ok;
+ while (len-- > 0) {
+ if ((result = Stream_writeDouble(stream, val)) != Stream_Ok) {
+ return result;
+ }
+ }
+ return result;
+}
+#endif // STREAM_DOUBLE
+/**
+ * @brief read array of characters
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readCharArray(Stream* stream, char* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readChar(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief read array of uint8_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readUInt8(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief read array of int8_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readInt8Array(Stream* stream, int8_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readInt8(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief read array of uint16_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readUInt16(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief read array of int16_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readInt16Array(Stream* stream, int16_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readInt16(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief read array of uint32_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readUInt32(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief read array of int32_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readInt32Array(Stream* stream, int32_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readInt32(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief read array of float
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readFloatArray(Stream* stream, float* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readFloat(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+#if STREAM_UINT64
+/**
+ * @brief read array of uint64_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readUInt64(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief read array of int64_t
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readInt64Array(Stream* stream, int64_t* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readInt64(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+/**
+ * @brief read array of double
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return Stream_Result
+ */
+Stream_Result Stream_readDoubleArray(Stream* stream, double* val, Stream_LenType len) {
+ if (Stream_available(stream) >= len) {
+ while (len-- > 0) {
+ *val++ = Stream_readDouble(stream);
+ }
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+#endif // STREAM_DOUBLE
+#if STREAM_WRITE_LOCK
+/**
+ * @brief lock the stream for writing
+ *
+ * @param stream
+ * @return Stream_Result
+ */
+Stream_Result Stream_lockWrite(Stream* stream, Stream* lock, Stream_LenType len) {
+ Stream_LenType space = Stream_space(stream);
+ if (space >= len && !stream->WriteLocked) {
+ __memCopy(stream, lock, stream, sizeof(Stream));
+ Stream_flipWrite(lock, len);
+ stream->WriteLocked = 1;
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoSpace;
+ }
+}
+/**
+ * @brief unlock the stream for writing
+ *
+ * @param stream
+ * @return Stream_Result
+ */
+void Stream_unlockWrite(Stream* stream, Stream* lock) {
+ if (stream->WriteLocked) {
+ Stream_moveWritePos(stream, Stream_lockWriteLen(stream, lock));
+ stream->WriteLocked = 0;
+ }
+}
+/**
+ * @brief unlock stream for write with ignore changes
+ *
+ * @param stream
+ */
+void Stream_unlockWriteIgnore(Stream* stream) {
+ if (stream->WriteLocked) {
+ stream->WriteLocked = 0;
+ }
+}
+/**
+ * @brief return number of byte write in lock
+ *
+ * @param stream
+ * @param lock
+ */
+Stream_LenType Stream_lockWriteLen(Stream* stream, Stream* lock) {
+ if (stream->WPos != lock->WPos) {
+ // some data wrote
+ if (stream->WPos < lock->WPos) {
+ return lock->WPos - stream->WPos;
+ }
+ else {
+ return (stream->Size - stream->WPos) + lock->WPos;
+ }
+ }
+ else if (stream->RPos == lock->RPos &&
+ stream->Overflow == 0 &&
+ lock->Overflow) {
+
+ return stream->Size;
+ }
+ else {
+ return 0;
+ }
+}
+#endif // STREAM_WRITE_LOCK
+
+#if STREAM_READ_LOCK
+/**
+ * @brief lock the stream for reading
+ *
+ * @param stream
+ * @return Stream_Result
+ */
+Stream_Result Stream_lockRead(Stream* stream, Stream* lock, Stream_LenType len) {
+ Stream_LenType available = Stream_available(stream);
+ if (available >= len && !stream->ReadLocked) {
+ __memCopy(stream, lock, stream, sizeof(Stream));
+ Stream_flipRead(lock, len);
+ stream->ReadLocked = 1;
+ return Stream_Ok;
+ }
+ else {
+ return Stream_NoAvailable;
+ }
+}
+/**
+ * @brief unlock the stream for reading
+ *
+ * @param stream
+ * @return Stream_Result
+ */
+void Stream_unlockRead(Stream* stream, Stream* lock) {
+ if (stream->ReadLocked) {
+ Stream_moveReadPos(stream, Stream_lockReadLen(stream, lock));
+ stream->ReadLocked = 0;
+ }
+}
+/**
+ * @brief return number of bytes that read
+ *
+ * @param stream
+ * @param lock
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_lockReadLen(Stream* stream, Stream* lock) {
+ if (stream->RPos != lock->RPos) {
+ // some data read
+ if (stream->RPos < lock->RPos) {
+ return lock->RPos - stream->RPos;
+ }
+ else {
+ return (stream->Size - stream->RPos) + lock->RPos;
+ }
+ }
+ else if (stream->WPos == lock->WPos &&
+ stream->Overflow != 0 &&
+ !lock->Overflow) {
+
+ return stream->Size;
+ }
+ else {
+ return 0;
+ }
+}
+/**
+ * @brief unlock stream for read with ignore changes
+ *
+ * @param stream
+ */
+void Stream_unlockReadIgnore(Stream* stream) {
+ if (stream->ReadLocked) {
+ stream->ReadLocked = 0;
+ }
+}
+#endif // STREAM_READ_LOCK
+
+#if STREAM_FIND_FUNCTIONS
+Stream_LenType Stream_findByte(Stream* stream, uint8_t val) {
+ Stream_LenType tmpLen = 0;
+ uint8_t* pStart = &stream->Data[stream->RPos];
+ uint8_t* pEnd;
+
+ if (Stream_available(stream) == 0) {
+ return -1;
+ }
+
+ pEnd = memchr(pStart, val, Stream_directAvailable(stream));
+ if (!pEnd && stream->Overflow) {
+ tmpLen = stream->Size - stream->RPos;
+ pStart = stream->Data;
+ pEnd = memchr(pStart, val, stream->WPos);
+ }
+
+ return pEnd != NULL ? (Stream_LenType)(pEnd - pStart) + tmpLen : -1;
+}
+Stream_LenType Stream_findByteAt(Stream* stream, Stream_LenType offset, uint8_t val) {
+ Stream_LenType tmpLen = 0;
+ uint8_t* pStart = Stream_getReadPtrAt(stream, offset);
+ uint8_t* pEnd;
+
+ if (Stream_available(stream) < offset) {
+ return -1;
+ }
+
+ tmpLen = Stream_directAvailableAt(stream, offset);
+ pEnd = memchr(pStart, val, tmpLen);
+ if (!pEnd && (tmpLen + offset) < Stream_available(stream)) {
+ pStart = stream->Data;
+ pEnd = memchr(pStart, val, stream->WPos);
+ }
+
+ return pEnd != NULL ? (Stream_LenType)(pEnd - pStart) + offset : -1;
+}
+Stream_LenType Stream_findPattern(Stream* stream, const uint8_t* pat, Stream_LenType patLen) {
+ Stream_LenType index = 0;
+
+ if (Stream_available(stream) < patLen) {
+ return -1;
+ }
+
+ while ((index = Stream_findByteAt(stream, index, *pat)) != -1) {
+ if (Stream_compareAt(stream, index, pat, patLen) == 0) {
+ break;
+ }
+ index++;
+ }
+
+ return index;
+}
+Stream_LenType Stream_findPatternAt(Stream* stream, Stream_LenType offset, const uint8_t* pat, Stream_LenType patLen) {
+ if (Stream_available(stream) < patLen) {
+ return -1;
+ }
+
+ while ((offset = Stream_findByteAt(stream, offset, *pat)) != -1) {
+ if (Stream_compareAt(stream, offset, pat, patLen) == 0) {
+ break;
+ }
+ offset++;
+ }
+
+ return offset;
+}
+Stream_LenType Stream_readBytesUntil(Stream* stream, uint8_t end, uint8_t* val, Stream_LenType len) {
+ Stream_LenType tmpLen;
+ // find end byte
+ if ((tmpLen = Stream_findByte(stream, end)) >= 0) {
+ tmpLen++;
+
+ if (len < tmpLen) {
+ tmpLen = len;
+ }
+
+ if (Stream_readBytes(stream, val, tmpLen) == Stream_Ok) {
+ return tmpLen;
+ }
+ }
+
+ return 0;
+}
+Stream_LenType Stream_readBytesUntilPattern(Stream* stream, const uint8_t* pat, Stream_LenType patLen, uint8_t* val, Stream_LenType len) {
+ Stream_LenType tmpLen;
+ // find end byte
+ if ((tmpLen = Stream_findPattern(stream, pat, patLen)) >= 0) {
+ tmpLen += patLen;
+
+ if (len < tmpLen) {
+ tmpLen = len;
+ }
+
+ if (Stream_readBytes(stream, val, tmpLen) == Stream_Ok) {
+ return tmpLen;
+ }
+ }
+
+ return 0;
+}
+/**
+ * @brief find a uint8_t value in stream
+ *
+ * @param stream
+ * @param val
+ * @return Stream_LenType
+ */
+Stream_LenType Stream_findUInt8(Stream* stream, uint8_t val) {
+ return Stream_findByte(stream, val);
+}
+Stream_LenType Stream_findInt8(Stream* stream, int8_t val) {
+ return Stream_findByte(stream, (uint8_t) val);
+}
+Stream_LenType Stream_findUInt16(Stream* stream, uint16_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findInt16(Stream* stream, int16_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findUInt32(Stream* stream, uint32_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findInt32(Stream* stream, int32_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val));
+}
+#if STREAM_UINT64
+Stream_LenType Stream_findUInt64(Stream* stream, uint64_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findInt64(Stream* stream, int64_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val));
+}
+#endif
+Stream_LenType Stream_findFloat(Stream* stream, float val) {
+ __checkReverse(stream, val);
+ return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val));
+}
+#if STREAM_DOUBLE
+Stream_LenType Stream_findDouble(Stream* stream, double val) {
+ __checkReverse(stream, val);
+ return Stream_findPattern(stream, (uint8_t*) &val, sizeof(val));
+}
+#endif
+
+#if STREAM_FIND_AT_FUNCTIONS
+Stream_LenType Stream_findUInt8At(Stream* stream, Stream_LenType offset, uint8_t val) {
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findInt8At(Stream* stream, Stream_LenType offset, int8_t val) {
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findUInt16At(Stream* stream, Stream_LenType offset, uint16_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findInt16At(Stream* stream, Stream_LenType offset, int16_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findUInt32At(Stream* stream, Stream_LenType offset, uint32_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findInt32At(Stream* stream, Stream_LenType offset, int32_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+#if STREAM_UINT64
+Stream_LenType Stream_findUInt64At(Stream* stream, Stream_LenType offset, uint64_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+Stream_LenType Stream_findInt64At(Stream* stream, Stream_LenType offset, int64_t val) {
+ __checkReverse(stream, val);
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+#endif
+Stream_LenType Stream_findFloatAt(Stream* stream, Stream_LenType offset, float val) {
+ __checkReverse(stream, val);
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+#if STREAM_DOUBLE
+Stream_LenType Stream_findDoubleAt(Stream* stream, Stream_LenType offset, double val) {
+ __checkReverse(stream, val);
+ return Stream_findPatternAt(stream, offset, (uint8_t*) &val, sizeof(val));
+}
+#endif
+#endif // STREAM_FIND_AT_FUNCTIONS
+
+#endif // STREAM_FIND_FUNCTIONS
+
+/**
+ * @brief compare a given bytes at index with available bytes in stream
+ *
+ * @param stream
+ * @param val
+ * @param len
+ * @return int8_t
+ */
+int8_t Stream_compare(Stream* stream, const uint8_t* val, Stream_LenType len) {
+ return Stream_compareAt(stream, 0, val, len);
+}
+/**
+ * @brief compare a given bytes at index with available bytes in stream
+ *
+ * @param stream
+ * @param index
+ * @param val
+ * @param len
+ * @return int8_t
+ */
+int8_t Stream_compareAt(Stream* stream, Stream_LenType index, const uint8_t* val, Stream_LenType len) {
+ int8_t result;
+ Stream_LenType tmpLen;
+
+ if (len == 0) {
+ return 0;
+ }
+
+ if (Stream_available(stream) - index < len) {
+ return -2;
+ }
+
+ tmpLen = Stream_directAvailableAt(stream, index);
+ if (tmpLen < len) {
+ if ((result = (int8_t) memcmp(Stream_getReadPtrAt(stream, index), val, tmpLen)) != 0) {
+ return result;
+ }
+
+ index += tmpLen;
+ val += tmpLen;
+ len -= tmpLen;
+ }
+
+ return (int8_t) memcmp(Stream_getReadPtrAt(stream, index), val, len);
+}
+// TODO: need to implement with more performance
+static void memrcpy(void* dest, const void* src, int len) {
+ uint8_t* pDest = (uint8_t*) dest;
+ const uint8_t* pSrc = (const uint8_t*) src + len - 1;
+
+ while (len-- > 0) {
+ *pDest++ = *pSrc--;
+ }
+}
+static void memreverse(void* arr, int len) {
+ uint8_t* pDest = (uint8_t*) arr;
+ uint8_t* pSrc = (uint8_t*) arr + len - 1;
+ uint8_t temp;
+
+ len >>= 1;
+ while (len-- > 0) {
+ temp = *pSrc;
+ *pSrc++ = *pDest;
+ *pDest-- = temp;
+ }
+}
diff --git a/Examples/StreamOverSocket/Stream/StreamBuffer.h b/Examples/StreamOverSocket/Stream/StreamBuffer.h
new file mode 100644
index 0000000..4bd260a
--- /dev/null
+++ b/Examples/StreamOverSocket/Stream/StreamBuffer.h
@@ -0,0 +1,538 @@
+/**
+ * @file StreamBuffer.h
+ * @author Ali Mirghasemi (ali.mirghasemi1376@gmail.com)
+ * @brief this library implement stream buffer with read & write operations
+ * @version 0.5
+ * @date 2021-09-01
+ *
+ * @copyright Copyright (c) 2021
+ *
+ */
+#ifndef _STREAM_H_
+#define _STREAM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+#define STREAM_VER_MAJOR 0
+#define STREAM_VER_MINOR 6
+#define STREAM_VER_FIX 0
+
+/************************************************************************/
+/* Configuration */
+/************************************************************************/
+
+/**
+ * @brief you can enable ByteOrder option to have r/w operation
+ * on what endian you need
+ */
+#define STREAM_BYTE_ORDER 1
+#if STREAM_BYTE_ORDER
+ /**
+ * @brief save system byte order in static variable for avoid calculate each time
+ * run Stream_getSystemByteOrder function
+ */
+ #define STREAM_BYTE_ORDER_SYS_STATIC 1
+#endif
+/**
+ * @brief enable set limit for write functions
+ */
+#define STREAM_WRITE_LIMIT 1
+/**
+ * @brief enable set limit for read operations
+ */
+#define STREAM_READ_LIMIT 1
+/**
+ * @brief enable write lock feature
+ */
+#define STREAM_WRITE_LOCK 1
+/**
+ * @brief enable read lock feature
+ */
+#define STREAM_READ_LOCK 1
+/**
+ * @brief enable cursor object for check how many bytes read or write
+ */
+#define STREAM_CURSOR 0
+/**
+ * @brief if your platform support 64bit variables and you need it
+ * you can enable this option
+ */
+#define STREAM_UINT64 1
+/**
+ * @brief if you need r/w double variables and your platform support
+ * you can enable this option
+ */
+#define STREAM_DOUBLE 1
+/**
+ * @brief enable get functions
+ */
+#define STREAM_GET_FUNCTIONS 1
+/**
+ * @brief enable getAt functions
+ */
+#define STREAM_GET_AT_FUNCTIONS 1
+/**
+ * @brief enable find functions
+ */
+#define STREAM_FIND_FUNCTIONS 1
+/**
+ * @brief enable findAt functions
+ */
+#define STREAM_FIND_AT_FUNCTIONS 1
+/**
+ * @brief check len parameter in read/write functions
+ */
+#define STREAM_CHECK_ZERO_LEN 1
+/* Stream Memory IO States */
+#define STREAM_MEM_IO_DEFAULT 0
+#define STREAM_MEM_IO_CUSTOM 1
+#define STREAM_MEM_IO_DRIVER 2
+/**
+ * @brief This features help you to override memcpy, memrcpy, memset and etc with your custom functions
+ */
+#define STREAM_MEM_IO STREAM_MEM_IO_DEFAULT
+/* Default IO functions */
+#define STREAM_MEM_COPY memcpy
+#define STREAM_MEM_COPY_REVERSE memrcpy
+#define STREAM_MEM_SET memset
+#define STREAM_MEM_REVERSE memreverse
+/**
+ * @brief based on maximum size of buffer that you use for stream
+ * you can change type of len variables
+ * must be signed type
+ */
+typedef int16_t Stream_LenType;
+
+/************************************************************************/
+
+#define __STREAM_VER_STR(major, minor, fix) #major "." #minor "." #fix
+#define _STREAM_VER_STR(major, minor, fix) __STREAM_VER_STR(major, minor, fix)
+/**
+ * @brief show stream version in string format
+ */
+#define STREAM_VER_STR _STREAM_VER_STR(STREAM_VER_MAJOR, STREAM_VER_MINOR, STREAM_VER_FIX)
+/**
+ * @brief show stream version in integer format, ex: 0.2.0 -> 200
+ */
+#define STREAM_VER ((STREAM_VER_MAJOR * 10000UL) + (STREAM_VER_MINOR * 100UL) + (STREAM_VER_FIX))
+
+/**
+ * @brief use for disable limit
+ */
+#define STREAM_NO_LIMIT -1
+
+/**
+ * @brief default value for read function if cause error
+ */
+#define STREAM_READ_DEFAULT_VALUE 0
+
+/**
+ * @brief you can choose what ByteOrder can use for r/w operations
+ */
+typedef enum {
+ ByteOrder_LittleEndian = 0, /**< little endian */
+ ByteOrder_BigEndian = 1, /**< big endian */
+ ByteOrder_Reserved = 0x0F,
+} ByteOrder;
+/**
+ * @brief result of Stream functions
+ */
+typedef enum {
+ Stream_Ok = 0, /**< everything is OK */
+ Stream_NoSpace = 1, /**< there is no space for write operation */
+ Stream_NoAvailable = 2, /**< there no available bytes for read operation */
+ Stream_BufferFull = 3, /**< buffer full*/
+ Stream_NoReceiveFn = 4, /**< no receive function set for IStream */
+ Stream_NoTransmitFn = 5, /**< no transmit function set for OStream */
+ Stream_NoReceive = 6, /**< stream is not in receive mode */
+ Stream_NoTransmit = 7, /**< stream is not in transmit mode */
+ Stream_InReceive = 8, /**< stream is in receive mode */
+ Stream_InTransmit = 9, /**< stream is in transmit mode */
+ Stream_ZeroLen = 10, /**< len parameter is zero */
+ Stream_ReceiveFailed = 11, /**< failed in receive */
+ Stream_TransmitFailed = 12, /**< failed in transmit */
+ Stream_CustomError = 0x80, /**< can be used for custom errors */
+} Stream_Result;
+/**
+ * @brief describe flush mode, use in OStream
+ */
+typedef enum {
+ Stream_FlushMode_Single = 0, /**< flush only pending bytes before call flush function */
+ Stream_FlushMode_Continue = 1, /**< after flush complete if there is any pending bytes transmit pending bytes again */
+} Stream_FlushMode;
+/**
+ * @brief Custom memcpy for override default function
+ */
+typedef Stream_LenType (*Stream_MemCopyFn)(void* dest, const void* src, Stream_LenType len);
+/**
+ * @brief Custom memrcpy for override default function
+ */
+typedef Stream_LenType (*Stream_MemCopyReverseFn)(void* dest, const void* src, Stream_LenType len);
+/**
+ * @brief Custom memset for override default function
+ */
+typedef Stream_LenType (*Stream_MemSetFn)(void* src, uint8_t val, Stream_LenType len);
+/**
+ * @brief Custom memset for override default function
+ */
+typedef Stream_LenType (*Stream_MemReverseFn)(void* src, Stream_LenType len);
+
+typedef struct {
+ Stream_MemCopyFn copy;
+ Stream_MemCopyReverseFn copyReverse;
+ Stream_MemSetFn set;
+ Stream_MemReverseFn reverse;
+} Stream_MemIO;
+
+/**
+ * @brief Stream struct
+ * contains everything need for handle stream
+ */
+typedef struct {
+#if STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM
+ Stream_MemIO Mem; /**< Custom io functions for interact with memory */
+#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER
+ const Stream_MemIO* Mem; /**< Custom io functions for interact with memory in driver mode */
+#endif
+ uint8_t* Data; /**< pointer to buffer */
+ Stream_LenType Size; /**< size of buffer */
+ Stream_LenType WPos; /**< write position */
+ Stream_LenType RPos; /**< read position */
+#if STREAM_WRITE_LIMIT
+ Stream_LenType WriteLimit; /**< limit for write operation */
+#endif // STREAM_WRITE_LIMIT
+#if STREAM_READ_LIMIT
+ Stream_LenType ReadLimit; /**< limit for read operation */
+#endif
+ uint8_t Overflow : 1; /**< overflow flag */
+ uint8_t InReceive : 1; /**< stream is in receive mode */
+ uint8_t InTransmit : 1; /**< stream is in transmit mode */
+ uint8_t Order : 1; /**< byte order */
+ uint8_t OrderFn : 1; /**< byte order function */
+ uint8_t WriteLocked : 1; /**< stream write locked */
+ uint8_t ReadLocked : 1; /**< stream write locked */
+ uint8_t FlushMode : 1; /**< flush mode */
+} Stream;
+/**
+ * @brief hold properties of cursor over stream
+ */
+typedef struct {
+ Stream_LenType WPos;
+ Stream_LenType RPos;
+} Stream_Cursor;
+
+void Stream_init(Stream* stream, uint8_t* buffer, Stream_LenType size);
+void Stream_fromBuff(Stream* stream, uint8_t* buffer, Stream_LenType size);
+void Stream_deinit(Stream* stream);
+
+#if STREAM_MEM_IO == STREAM_MEM_IO_CUSTOM
+void Stream_setMemIO(
+ Stream* stream,
+ Stream_MemCopyFn copy,
+ Stream_MemCopyReverseFn copyReverse,
+ Stream_MemSetFn set,
+ Stream_MemReverseFn reverse
+);
+#elif STREAM_MEM_IO == STREAM_MEM_IO_DRIVER
+void Stream_setMemIO(Stream* stream, const Stream_MemIO* mem);
+#endif
+
+/*************** General APIs *************/
+
+#if STREAM_WRITE_LIMIT
+ #define Stream_space(STREAM) Stream_spaceLimit((STREAM))
+#else
+ #define Stream_space(STREAM) Stream_spaceReal((STREAM))
+#endif // STREAM_WRITE_LIMIT
+
+#if STREAM_READ_LIMIT
+ #define Stream_available(STREAM) Stream_availableLimit((STREAM))
+#else
+ #define Stream_available(STREAM) Stream_availableReal((STREAM))
+#endif // STREAM_READ_LIMIT
+
+Stream_LenType Stream_availableReal(Stream* stream);
+Stream_LenType Stream_spaceReal(Stream* stream);
+uint8_t Stream_isEmpty(Stream* stream);
+uint8_t Stream_isFull(Stream* stream);
+
+Stream_LenType Stream_directAvailable(Stream* stream);
+Stream_LenType Stream_directSpace(Stream* stream);
+
+Stream_LenType Stream_directAvailableAt(Stream* stream, Stream_LenType index);
+Stream_LenType Stream_directSpaceAt(Stream* stream, Stream_LenType index);
+
+uint8_t* Stream_getWritePtr(Stream* stream);
+uint8_t* Stream_getReadPtr(Stream* stream);
+uint8_t* Stream_getWritePtrAt(Stream* stream, Stream_LenType index);
+uint8_t* Stream_getReadPtrAt(Stream* stream, Stream_LenType index);
+
+void Stream_reset(Stream* stream);
+void Stream_resetIO(Stream* stream);
+void Stream_clear(Stream* stream);
+
+void Stream_setFlushMode(Stream* stream, Stream_FlushMode mode);
+
+uint8_t Stream_inReceive(Stream* stream);
+uint8_t Stream_inTransmit(Stream* stream);
+
+uint8_t* Stream_getBuffer(Stream* stream);
+
+void Stream_setBuffer(Stream* stream, uint8_t* data, Stream_LenType size);
+Stream_LenType Stream_getBufferSize(Stream* stream);
+
+Stream_LenType Stream_getWritePos(Stream* stream);
+Stream_LenType Stream_getReadPos(Stream* stream);
+
+Stream_Result Stream_moveWritePos(Stream* stream, Stream_LenType steps);
+Stream_Result Stream_moveReadPos(Stream* stream, Stream_LenType steps);
+
+void Stream_flipWrite(Stream* stream, Stream_LenType len);
+void Stream_flipRead(Stream* stream, Stream_LenType len);
+
+#if STREAM_BYTE_ORDER
+ ByteOrder Stream_getSystemByteOrder(void);
+ void Stream_setByteOrder(Stream* stream, ByteOrder order);
+ ByteOrder Stream_getByteOrder(Stream* stream);
+#endif // STREAM_BYTE_ORDER
+
+#if STREAM_WRITE_LIMIT
+ void Stream_setWriteLimit(Stream* stream, Stream_LenType len);
+ uint8_t Stream_isWriteLimited(Stream* stream);
+ Stream_LenType Stream_spaceLimit(Stream* stream);
+ Stream_LenType Stream_getWriteLimit(Stream* stream);
+#endif // STREAM_WRITE_LIMIT
+
+#if STREAM_READ_LIMIT
+ void Stream_setReadLimit(Stream* stream, Stream_LenType len);
+ uint8_t Stream_isReadLimited(Stream* stream);
+ Stream_LenType Stream_availableLimit(Stream* stream);
+ Stream_LenType Stream_getReadLimit(Stream* stream);
+#endif // STREAM_READ_LIMIT
+
+#if STREAM_CURSOR
+ void Stream_getCursor(Stream* stream, Stream_Cursor* cursor);
+ Stream_LenType Stream_getReadLen(Stream* stream, Stream_Cursor* cursor);
+ Stream_LenType Stream_getWriteLen(Stream* stream, Stream_Cursor* cursor);
+#endif // STREAM_CURSOR
+
+#if STREAM_WRITE_LOCK
+ Stream_Result Stream_lockWrite(Stream* stream, Stream* lock, Stream_LenType len);
+ void Stream_unlockWrite(Stream* stream, Stream* lock);
+ void Stream_unlockWriteIgnore(Stream* stream);
+ Stream_LenType Stream_lockWriteLen(Stream* stream, Stream* lock);
+#endif // STREAM_WRITE_LOCK
+
+#if STREAM_READ_LOCK
+ Stream_Result Stream_lockRead(Stream* stream, Stream* lock, Stream_LenType len);
+ void Stream_unlockRead(Stream* stream, Stream* lock);
+ void Stream_unlockReadIgnore(Stream* stream);
+ Stream_LenType Stream_lockReadLen(Stream* stream, Stream* lock);
+#endif // STREAM_READ_LOCK
+
+/**************** Write APIs **************/
+Stream_Result Stream_writeBytes(Stream* stream, uint8_t* val, Stream_LenType len);
+Stream_Result Stream_writeBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len);
+Stream_Result Stream_writeChar(Stream* stream, char val);
+Stream_Result Stream_writeStr(Stream* stream, const char* val);
+Stream_Result Stream_writeUInt8(Stream* stream, uint8_t val);
+Stream_Result Stream_writeInt8(Stream* stream, int8_t val);
+Stream_Result Stream_writeUInt16(Stream* stream, uint16_t val);
+Stream_Result Stream_writeInt16(Stream* stream, int16_t val);
+Stream_Result Stream_writeUInt32(Stream* stream, uint32_t val);
+Stream_Result Stream_writeInt32(Stream* stream, int32_t val);
+Stream_Result Stream_writeFloat(Stream* stream, float val);
+#if STREAM_UINT64
+ Stream_Result Stream_writeUInt64(Stream* stream, uint64_t val);
+ Stream_Result Stream_writeInt64(Stream* stream, int64_t val);
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ Stream_Result Stream_writeDouble(Stream* stream, double val);
+#endif // STREAM_DOUBLE
+
+Stream_Result Stream_writeCharArray(Stream* stream, char* val, Stream_LenType len);
+Stream_Result Stream_writeUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len);
+Stream_Result Stream_writeInt8Array(Stream* stream, int8_t* val, Stream_LenType len);
+Stream_Result Stream_writeUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len);
+Stream_Result Stream_writeInt16Array(Stream* stream, int16_t* val, Stream_LenType len);
+Stream_Result Stream_writeUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len);
+Stream_Result Stream_writeInt32Array(Stream* stream, int32_t* val, Stream_LenType len);
+Stream_Result Stream_writeFloatArray(Stream* stream, float* val, Stream_LenType len);
+#if STREAM_UINT64
+ Stream_Result Stream_writeUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len);
+ Stream_Result Stream_writeInt64Array(Stream* stream, int64_t* val, Stream_LenType len);
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ Stream_Result Stream_writeDoubleArray(Stream* stream, double val, Stream_LenType len);
+#endif // STREAM_DOUBLE
+
+Stream_Result Stream_writeStream(Stream* out, Stream* in, Stream_LenType len);
+
+Stream_Result Stream_writePadding(Stream* stream, uint8_t val, Stream_LenType len);
+
+/**************** Read APIs **************/
+int16_t Stream_read(Stream* stream);
+Stream_Result Stream_readBytes(Stream* stream, uint8_t* val, Stream_LenType len);
+Stream_Result Stream_readBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len);
+char Stream_readChar(Stream* stream);
+uint8_t Stream_readUInt8(Stream* stream);
+int8_t Stream_readInt8(Stream* stream);
+uint16_t Stream_readUInt16(Stream* stream);
+int16_t Stream_readInt16(Stream* stream);
+uint32_t Stream_readUInt32(Stream* stream);
+int32_t Stream_readInt32(Stream* stream);
+float Stream_readFloat(Stream* stream);
+#if STREAM_UINT64
+ uint64_t Stream_readUInt64(Stream* stream);
+ int64_t Stream_readInt64(Stream* stream);
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ double Stream_readDouble(Stream* stream);
+#endif // STREAM_DOUBLE
+
+Stream_Result Stream_readCharArray(Stream* stream, char* val, Stream_LenType len);
+Stream_Result Stream_readUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len);
+Stream_Result Stream_readInt8Array(Stream* stream, int8_t* val, Stream_LenType len);
+Stream_Result Stream_readUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len);
+Stream_Result Stream_readInt16Array(Stream* stream, int16_t* val, Stream_LenType len);
+Stream_Result Stream_readUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len);
+Stream_Result Stream_readInt32Array(Stream* stream, int32_t* val, Stream_LenType len);
+Stream_Result Stream_readFloatArray(Stream* stream, float* val, Stream_LenType len);
+#if STREAM_UINT64
+ Stream_Result Stream_readUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len);
+ Stream_Result Stream_readInt64Array(Stream* stream, int64_t* val, Stream_LenType len);
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ Stream_Result Stream_readDoubleArray(Stream* stream, double* val, Stream_LenType len);
+#endif // STREAM_DOUBLE
+
+Stream_Result Stream_readStream(Stream* in, Stream* out, Stream_LenType len);
+
+#if STREAM_GET_AT_FUNCTIONS && STREAM_GET_FUNCTIONS
+Stream_Result Stream_getBytes(Stream* stream, uint8_t* val, Stream_LenType len);
+Stream_Result Stream_getBytesReverse(Stream* stream, uint8_t* val, Stream_LenType len);
+char Stream_getChar(Stream* stream);
+uint8_t Stream_getUInt8(Stream* stream);
+int8_t Stream_getInt8(Stream* stream);
+uint16_t Stream_getUInt16(Stream* stream);
+int16_t Stream_getInt16(Stream* stream);
+uint32_t Stream_getUInt32(Stream* stream);
+int32_t Stream_getInt32(Stream* stream);
+float Stream_getFloat(Stream* stream);
+#if STREAM_UINT64
+ uint64_t Stream_getUInt64(Stream* stream);
+ int64_t Stream_getInt64(Stream* stream);
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ double Stream_getDouble(Stream* stream);
+#endif // STREAM_DOUBLE
+
+Stream_Result Stream_getCharArray(Stream* stream, char* val, Stream_LenType len);
+Stream_Result Stream_getUInt8Array(Stream* stream, uint8_t* val, Stream_LenType len);
+Stream_Result Stream_getInt8Array(Stream* stream, int8_t* val, Stream_LenType len);
+Stream_Result Stream_getUInt16Array(Stream* stream, uint16_t* val, Stream_LenType len);
+Stream_Result Stream_getInt16Array(Stream* stream, int16_t* val, Stream_LenType len);
+Stream_Result Stream_getUInt32Array(Stream* stream, uint32_t* val, Stream_LenType len);
+Stream_Result Stream_getInt32Array(Stream* stream, int32_t* val, Stream_LenType len);
+Stream_Result Stream_getFloatArray(Stream* stream, float* val, Stream_LenType len);
+#if STREAM_UINT64
+ Stream_Result Stream_getUInt64Array(Stream* stream, uint64_t* val, Stream_LenType len);
+ Stream_Result Stream_getInt64Array(Stream* stream, int64_t* val, Stream_LenType len);
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ Stream_Result Stream_getDoubleArray(Stream* stream, double* val, Stream_LenType len);
+#endif // STREAM_DOUBLE
+
+#endif // STREAM_GET_FUNCTIONS
+
+#if STREAM_GET_AT_FUNCTIONS
+
+Stream_Result Stream_getBytesAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len);
+Stream_Result Stream_getBytesReverseAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len);
+char Stream_getCharAt(Stream* stream, Stream_LenType index);
+uint8_t Stream_getUInt8At(Stream* stream, Stream_LenType index);
+int8_t Stream_getInt8At(Stream* stream, Stream_LenType index);
+uint16_t Stream_getUInt16At(Stream* stream, Stream_LenType index);
+int16_t Stream_getInt16At(Stream* stream, Stream_LenType index);
+uint32_t Stream_getUInt32At(Stream* stream, Stream_LenType index);
+int32_t Stream_getInt32At(Stream* stream, Stream_LenType index);
+float Stream_getFloatAt(Stream* stream, Stream_LenType index);
+#if STREAM_UINT64
+ uint64_t Stream_getUInt64At(Stream* stream, Stream_LenType index);
+ int64_t Stream_getInt64At(Stream* stream, Stream_LenType index);
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ double Stream_getDoubleAt(Stream* stream, Stream_LenType index);
+#endif // STREAM_DOUBLE
+
+Stream_Result Stream_getCharArrayAt(Stream* stream, Stream_LenType index, char* val, Stream_LenType len);
+Stream_Result Stream_getUInt8ArrayAt(Stream* stream, Stream_LenType index, uint8_t* val, Stream_LenType len);
+Stream_Result Stream_getInt8ArrayAt(Stream* stream, Stream_LenType index, int8_t* val, Stream_LenType len);
+Stream_Result Stream_getUInt16ArrayAt(Stream* stream, Stream_LenType index, uint16_t* val, Stream_LenType len);
+Stream_Result Stream_getInt16ArrayAt(Stream* stream, Stream_LenType index, int16_t* val, Stream_LenType len);
+Stream_Result Stream_getUInt32ArrayAt(Stream* stream, Stream_LenType index, uint32_t* val, Stream_LenType len);
+Stream_Result Stream_getInt32ArrayAt(Stream* stream, Stream_LenType index, int32_t* val, Stream_LenType len);
+Stream_Result Stream_getFloatArrayAt(Stream* stream, Stream_LenType index, float* val, Stream_LenType len);
+#if STREAM_UINT64
+ Stream_Result Stream_getUInt64ArrayAt(Stream* stream, Stream_LenType index, uint64_t* val, Stream_LenType len);
+ Stream_Result Stream_getInt64ArrayAt(Stream* stream, Stream_LenType index, int64_t* val, Stream_LenType len);
+#endif // STREAM_UINT64
+#if STREAM_DOUBLE
+ Stream_Result Stream_getDoubleArrayAt(Stream* stream, Stream_LenType index, double* val, Stream_LenType len);
+#endif // STREAM_DOUBLE
+
+#endif // STREAM_GET_AT_FUNCTION
+
+#if STREAM_FIND_FUNCTIONS
+ Stream_LenType Stream_findByte(Stream* stream, uint8_t val);
+ Stream_LenType Stream_findByteAt(Stream* stream, Stream_LenType offset, uint8_t val);
+ Stream_LenType Stream_findPattern(Stream* stream, const uint8_t* pat, Stream_LenType patLen);
+ Stream_LenType Stream_findPatternAt(Stream* stream, Stream_LenType offset, const uint8_t* pat, Stream_LenType patLen);
+ Stream_LenType Stream_findUInt8(Stream* stream, uint8_t val);
+ Stream_LenType Stream_findInt8(Stream* stream, int8_t val);
+ Stream_LenType Stream_findUInt16(Stream* stream, uint16_t val);
+ Stream_LenType Stream_findInt16(Stream* stream, int16_t val);
+ Stream_LenType Stream_findUInt32(Stream* stream, uint32_t val);
+ Stream_LenType Stream_findInt32(Stream* stream, int32_t val);
+#if STREAM_UINT64
+ Stream_LenType Stream_findUInt64(Stream* stream, uint64_t val);
+ Stream_LenType Stream_findInt64(Stream* stream, int64_t val);
+#endif
+ Stream_LenType Stream_findFloat(Stream* stream, float val);
+#if STREAM_DOUBLE
+ Stream_LenType Stream_findDouble(Stream* stream, double val);
+#endif
+
+#if STREAM_FIND_AT_FUNCTIONS
+ Stream_LenType Stream_findUInt8At(Stream* stream, Stream_LenType offset, uint8_t val);
+ Stream_LenType Stream_findInt8At(Stream* stream, Stream_LenType offset, int8_t val);
+ Stream_LenType Stream_findUInt16At(Stream* stream, Stream_LenType offset, uint16_t val);
+ Stream_LenType Stream_findInt16At(Stream* stream, Stream_LenType offset, int16_t val);
+ Stream_LenType Stream_findUInt32At(Stream* stream, Stream_LenType offset, uint32_t val);
+ Stream_LenType Stream_findInt32At(Stream* stream, Stream_LenType offset, int32_t val);
+#if STREAM_UINT64
+ Stream_LenType Stream_findUInt64At(Stream* stream, Stream_LenType offset, uint64_t val);
+ Stream_LenType Stream_findInt64At(Stream* stream, Stream_LenType offset, int64_t val);
+#endif
+ Stream_LenType Stream_findFloatAt(Stream* stream, Stream_LenType offset, float val);
+#if STREAM_DOUBLE
+ Stream_LenType Stream_findDoubleAt(Stream* stream, Stream_LenType offset, double val);
+#endif
+#endif // STREAM_FIND_AT_FUNCTIONS
+
+ Stream_LenType Stream_readBytesUntil(Stream* stream, uint8_t end, uint8_t* val, Stream_LenType len);
+ Stream_LenType Stream_readBytesUntilPattern(Stream* stream, const uint8_t* pat, Stream_LenType patLen, uint8_t* val, Stream_LenType len);
+#endif // STREAM_FIND_FUNCTIONS
+
+int8_t Stream_compare(Stream* stream, const uint8_t* val, Stream_LenType len);
+int8_t Stream_compareAt(Stream* stream, Stream_LenType index, const uint8_t* val, Stream_LenType len);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _STREAM_H_ */
diff --git a/Examples/StreamOverSocket/Stream/UARTStream.c b/Examples/StreamOverSocket/Stream/UARTStream.c
new file mode 100644
index 0000000..ecb98a2
--- /dev/null
+++ b/Examples/StreamOverSocket/Stream/UARTStream.c
@@ -0,0 +1,137 @@
+#include "UARTStream.h"
+
+/**
+ * @brief Initialize UARTStream object
+ *
+ * @param stream
+ * @param huart
+ * @param rxBuff
+ * @param rxBuffSize
+ * @param txBuff
+ * @param txBuffSize
+ */
+bool UARTStream_init(
+ UARTStream* stream, const char* ip, uint16_t port, const char* name,
+ uint8_t* rxBuff, Stream_LenType rxBuffSize,
+ uint8_t* txBuff, Stream_LenType txBuffSize
+) {
+
+ void * socketInit(void* args,const char* ip, uint16_t port, const char* name,void (*txComp)(void*),void (*rxComp)(void*));
+ void * ptr = socketInit(stream,ip,port,name,UARTStream_txHandle,UARTStream_rxHandle);
+ if(ptr == NULL){
+ return false;
+ }
+ stream->uartOverSock = ptr;
+
+ IStream_init(&stream->Input, UARTStream_receive, rxBuff, rxBuffSize);
+ IStream_setCheckReceive(&stream->Input, UARTStream_checkReceive);
+ IStream_setArgs(&stream->Input, stream);
+
+ OStream_init(&stream->Output, UARTStream_transmit, txBuff, txBuffSize);
+ OStream_setCheckTransmit(&stream->Output, UARTStream_checkTransmit);
+ OStream_setArgs(&stream->Output, stream);
+ return true;
+}
+
+void UARTStream_deInit(UARTStream* stream){
+ void socketDeInit(void *obj);
+ socketDeInit(stream->uartOverSock);
+}
+/**
+ * @brief Handle Receive Data for Input Stream, user must put it in
+ * HAL_UART_RxCpltCallback or other callbacks
+ *
+ * @param stream
+ */
+void UARTStream_rxHandle(void* ptr) {
+ UARTStream* stream = (UARTStream*)ptr;
+ IStream_handle(&stream->Input, IStream_incomingBytes(&stream->Input));
+}
+/**
+ * @brief Handle Transmit Data for Output Stream, user must put it in
+ * HAL_UART_TxCpltCallback or other callbacks
+ *
+ * @param stream
+ */
+void UARTStream_txHandle(void* ptr) {
+ UARTStream* stream = (UARTStream*)ptr;
+ OStream_handle(&stream->Output, OStream_outgoingBytes(&stream->Output));
+}
+/**
+ * @brief Check Received bytes in DMA or IT and add to stream
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType UARTStream_checkReceive(IStream* stream) {
+ UARTStream* uartStream = (UARTStream*) IStream_getArgs(stream);
+ // if (uartStream->HUART->hdmarx) {
+ // return IStream_incomingBytes(stream) - __HAL_DMA_GET_COUNTER(uartStream->HUART->hdmarx);
+ // }
+ // else {
+ // return IStream_incomingBytes(stream) - uartStream->HUART->RxXferCount;
+ // }
+ size_t socketinReceive(void *obj);
+ return IStream_incomingBytes(stream) - socketinReceive(uartStream->uartOverSock);
+}
+/**
+ * @brief Check Transmitted bytes in DMA or IT and removed from stream
+ *
+ * @param stream
+ * @return Stream_LenType
+ */
+Stream_LenType UARTStream_checkTransmit(OStream* stream) {
+ UARTStream* uartStream = (UARTStream*) OStream_getArgs(stream);
+ // if (uartStream->HUART->hdmarx) {
+ // return OStream_outgoingBytes(stream) - __HAL_DMA_GET_COUNTER(uartStream->HUART->hdmatx);
+ // }
+ // else {
+ // return OStream_outgoingBytes(stream) - uartStream->HUART->TxXferCount;
+ // }
+ return 0;
+}
+/**
+ * @brief Stream receive function
+ *
+ * @param stream
+ * @param buff
+ * @param len
+ */
+Stream_Result UARTStream_receive(IStream* stream, uint8_t* buff, Stream_LenType len) {
+ // HAL_StatusTypeDef status;
+ // UARTStream* uartStream = (UARTStream*) IStream_getArgs(stream);
+ // if (uartStream->HUART->hdmarx) {
+ // status = HAL_UART_Receive_DMA(uartStream->HUART, buff, len);
+ // }
+ // else {
+ // status = HAL_UART_Receive_IT(uartStream->HUART, buff, len);
+ // }
+ // return status == HAL_OK ? Stream_Ok : Stream_CustomError | status;
+ UARTStream* uartStream = (UARTStream*) IStream_getArgs(stream);
+ void socketReceive(void *obj, uint8_t *buffer, size_t len);
+ socketReceive(uartStream->uartOverSock,buff,len);
+ return 0;
+}
+/**
+ * @brief Stream transmit function
+ *
+ * @param stream
+ * @param buff
+ * @param len
+ */
+Stream_Result UARTStream_transmit(OStream* stream, uint8_t* buff, Stream_LenType len) {
+ // HAL_StatusTypeDef status;
+ // UARTStream* uartStream = (UARTStream*) OStream_getArgs(stream);
+ // if (uartStream->HUART->hdmatx) {
+ // status = HAL_UART_Transmit_DMA(uartStream->HUART, buff, len);
+ // }
+ // else {
+ // status = HAL_UART_Transmit_IT(uartStream->HUART, buff, len);
+ // }
+ // return status == HAL_OK ? Stream_Ok : Stream_CustomError | status;
+ UARTStream* uartStream = (UARTStream*) OStream_getArgs(stream);
+ void socketTransmit(void *obj, uint8_t *buffer, size_t len);
+ //printf("len = %d ",len);
+ socketTransmit(uartStream->uartOverSock,buff,len);
+ return 0;
+}
diff --git a/Examples/StreamOverSocket/Stream/UARTStream.h b/Examples/StreamOverSocket/Stream/UARTStream.h
new file mode 100644
index 0000000..19d980c
--- /dev/null
+++ b/Examples/StreamOverSocket/Stream/UARTStream.h
@@ -0,0 +1,76 @@
+/**
+ * @file UARTStream.h
+ * @author Ali Mirghasemi (ali.mirghasemi1376@gmail.com)
+ * @brief This library implement Stream library for STM32Fxxx Based on HAL
+ * @version 0.1
+ * @date 2023-01-07
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+#ifndef _UART_STREAM_H_
+#define _UART_STREAM_H_
+
+#include "InputStream.h"
+#include "OutputStream.h"
+#include "stdbool.h"
+
+/******************************************************************************/
+/* Configuration */
+/******************************************************************************/
+// #define UARTSTREAM_MCU_F0 0x00
+// #define UARTSTREAM_MCU_F1 0x01
+// #define UARTSTREAM_MCU_F2 0x02
+// #define UARTSTREAM_MCU_F3 0x03
+// #define UARTSTREAM_MCU_F4 0x04
+// #define UARTSTREAM_MCU_F7 0x07
+// #define UARTSTREAM_MCU_H7 0x17
+
+// /**
+// * @brief define your MCU series
+// */
+// #define UARTSTREAM_MCU UARTSTREAM_MCU_F4
+
+// /******************************************************************************/
+
+// #if UARTSTREAM_MCU == UARTSTREAM_MCU_F0
+// #include "stm32f0xx.h"
+// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F1
+// #include "stm32f1xx.h"
+// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F2
+// #include "stm32f2xx.h"
+// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F3
+// #include "stm32f3xx.h"
+// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F4
+// #include "stm32f4xx.h"
+// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_F7
+// #include "stm32f7xx.h"
+// #elif UARTSTREAM_MCU == UARTSTREAM_MCU_H7
+// #include "stm32h7xx.h"
+// #else
+// #error "Wrong MCU series!"
+// #endif
+
+typedef struct {
+ void * uartOverSock;
+ IStream Input;
+ OStream Output;
+} UARTStream;
+
+bool UARTStream_init(
+ UARTStream* stream, const char* ip, uint16_t port,const char* name,
+ uint8_t* rxBuff, Stream_LenType rxBuffSize,
+ uint8_t* txBuff, Stream_LenType txBuffSize
+);
+void UARTStream_deInit(UARTStream* stream);
+
+void UARTStream_rxHandle(void* ptr);
+void UARTStream_txHandle(void* ptr);
+
+Stream_LenType UARTStream_checkReceive(IStream* stream);
+Stream_LenType UARTStream_checkTransmit(OStream* stream);
+Stream_Result UARTStream_receive(IStream* stream, uint8_t* buff, Stream_LenType len);
+Stream_Result UARTStream_transmit(OStream* stream, uint8_t* buff, Stream_LenType len);
+
+#endif // _UART_STREAM_H_
+
diff --git a/Examples/StreamOverSocket/Stream/buffer.c b/Examples/StreamOverSocket/Stream/buffer.c
new file mode 100644
index 0000000..5e87bb7
--- /dev/null
+++ b/Examples/StreamOverSocket/Stream/buffer.c
@@ -0,0 +1,52 @@
+#include "buffer.h"
+
+
+uint8_t *_buffer;
+size_t _size;
+volatile size_t _head,_tail;
+void buffer_init(void * buffer,size_t len){
+ _buffer = buffer;
+ _size = len;
+ _head = _tail = 0;
+
+}
+
+size_t buffer_available(){
+ if(_head >= _tail){
+ return _head - _tail;
+ }
+ else {
+ return _size - _tail + _head ;
+ }
+
+}
+bool buffer_add(uint8_t* buffer ,size_t len){
+ if(len <= _size - buffer_available()){
+ for(size_t i=0;i
+
+void delay(uint32_t time)
+{
+ Sleep(time);
+}
+uint32_t millis()
+{
+ static uint32_t _startMillis;
+ if(_startMillis == 0){
+ _startMillis = GetTickCount();
+ return 0;
+ }
+ return GetTickCount() - _startMillis;
+}
+
+void replaceSpecialChar(char ch, uint8_t *buffer)
+{
+ switch (ch)
+ {
+ case '\r':
+ snprintf(buffer, 6, "\\r");
+ break;
+ case '\n':
+ snprintf(buffer, 6, "\\n");
+ break;
+ case '\t':
+ snprintf(buffer, 6, "\\t");
+ break;
+ case '\0':
+ snprintf(buffer, 6, "\\0");
+ break;
+ default:
+ snprintf(buffer, 6, "%c", ch); // Return the original character if it's not a special character
+ }
+}
+void print_arr_hex(uint8_t *buffer, int len)
+{
+ printf("array(%d)[ ", len);
+ for (int i = 0; i < len; i++)
+ {
+ printf("%02X", buffer[i]);
+ if (i != len - 1)
+ {
+ printf(" ");
+ }
+ }
+ printf(" ]");
+}
+void print_arr_norm(uint8_t *buffer, int len)
+{
+ uint8_t temp[6];
+ printf("array(%d)[ ", len);
+ for (int i = 0; i < len; i++)
+ {
+ replaceSpecialChar(buffer[i], temp);
+ printf("%s", temp);
+ if (i != len - 1)
+ {
+ }
+ }
+ printf(" ]");
+}
+void print_hex(uint8_t *buffer, int len)
+{
+ for (int i = 0; i < len; i++)
+ {
+ printf("%02X", buffer[i]);
+ if (i != len - 1)
+ {
+ printf(" ");
+ }
+ }
+}
+void print_norm(uint8_t *buffer, int len)
+{
+ uint8_t temp[6];
+ for (int i = 0; i < len; i++)
+ {
+ replaceSpecialChar(buffer[i], temp);
+ printf("%s", temp);
+ if (i != len - 1)
+ {
+ }
+ }
+}
+
+void print_f(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
+
diff --git a/Examples/StreamOverSocket/arduino/arduino.h b/Examples/StreamOverSocket/arduino/arduino.h
new file mode 100644
index 0000000..0f210e6
--- /dev/null
+++ b/Examples/StreamOverSocket/arduino/arduino.h
@@ -0,0 +1,20 @@
+#ifndef SERIALPORT_GENERAL_H
+#define SERIALPORT_GENERAL_H
+#include "stdint.h"
+#include "stdio.h"
+#include "stdarg.h"
+
+#define STR(X) X, strlen(X)
+#define STR_C(X) X, sizeof(X)-1
+
+void delay(uint32_t time);
+uint32_t millis();
+void print_arr_hex(uint8_t *buffer, int len);
+void print_arr_norm(uint8_t *buffer, int len);
+void print_hex(uint8_t *buffer, int len);
+void print_norm(uint8_t *buffer, int len);
+void print_f(const char *format, ...);
+
+
+
+#endif //SERIALPORT_GENERAL_H
diff --git a/Examples/StreamOverSocket/main.c b/Examples/StreamOverSocket/main.c
new file mode 100644
index 0000000..ca665e4
--- /dev/null
+++ b/Examples/StreamOverSocket/main.c
@@ -0,0 +1,63 @@
+#include
+#include
+#include
+#include "stdint.h"
+#include
+
+
+#pragma comment(lib, "ws2_32.lib")
+
+void setup();
+void loop();
+
+
+
+void* LoopThread(void *args)
+{
+ int sleepIndexer=0;
+ while (1)
+ {
+ loop();
+
+ sleepIndexer++;
+ if(sleepIndexer == 1000)
+ {
+ sleepIndexer = 0;
+ Sleep(1);
+ }
+ }
+ pthread_exit(NULL);
+}
+
+
+int main()
+{
+ WSADATA wsa;
+
+// printf("Initializing Winsock...\n");
+ if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
+ {
+ printf("Initializing Winsock Failed. Error Code: %d\n", WSAGetLastError());
+ return 0;
+ }
+
+// printf("Initialized.\n");
+ setup();
+
+
+ pthread_t loopThread;
+
+ // Create producer and consumer threads
+ int ret =pthread_create(&loopThread, NULL, LoopThread, NULL);
+ if(ret != 0){
+ printf("create loopThread Failed. Error Code: %d\n",ret);
+ }
+ else {
+ pthread_join(loopThread, NULL);
+ }
+ // Close the socket
+ // closesocket(s);
+ WSACleanup();
+
+ return 0;
+}
diff --git a/Examples/StreamOverSocket/serial_server.py b/Examples/StreamOverSocket/serial_server.py
new file mode 100644
index 0000000..d22760c
--- /dev/null
+++ b/Examples/StreamOverSocket/serial_server.py
@@ -0,0 +1,150 @@
+import socket
+import serial
+import threading
+import argparse
+
+BUFFER_SIZE = 1024
+
+# Parse command-line arguments
+parser = argparse.ArgumentParser(description="TCP server to pipe data between a TCP client and a serial port")
+parser.add_argument('-ip', '--ip-address', type=str, help="TCP server IP address", required=False,default='127.0.0.1')
+parser.add_argument('-p', '--port', type=int, help="TCP server port", required=False,default=8888)
+parser.add_argument('-com', '--com-port', type=str, help="Serial port name (e.g., COM1)", required=False,default='COM5')
+parser.add_argument('-b', '--baudrate', type=int, help="Serial port baud rate", required=False,default='115200')
+parser.add_argument('-tx', '--tx', type=str, help="file address to tx data in", required=False,default='')
+parser.add_argument('-rx', '--rx', type=str, help="file address to rx data in", required=False,default='')
+parser.add_argument("-v", "--verbose", help="Enable verbose mode", action="store_true")
+args = parser.parse_args()
+
+# Create a TCP socket server
+tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+tcp_server_socket.bind((args.ip_address, args.port))
+tcp_server_socket.listen(1)
+
+verbos = True
+if args.verbose:
+ verbos = True
+
+# def custom_decode(bytes_data):
+# special_chars = {
+# b"\n": "\\n",
+# b"\r": "\\r",
+# b"\t": "\\t",
+# b"\0": "\\0",
+# b"\x1A": "\\x1A", # Ctrl+Z
+# # Add more special characters as needed
+# }
+
+# decoded_str = bytes_data.decode("utf-8")
+
+# for char, escape_seq in special_chars.items():
+# decoded_str = decoded_str.replace(char.decode("utf-8"), escape_seq)
+
+# return decoded_str
+
+def custom_decode(byte_array):
+ decoded_chars = ""
+ special_chars = {
+ '\n': "\\n",
+ '\r': "\\r",
+ '\t': "\\t",
+ '\0': "\\0",
+
+ }
+
+ for byte in byte_array:
+ char = chr(byte)
+ if 32 <= ord(char) <= 126: # Filter only printable ASCII characters
+ decoded_chars+=(char)
+ elif char in ['\n','\r','\t','\0']:
+ decoded_chars += special_chars[char]
+ else :
+ decoded_chars += "\\x{:02x}".format(byte)
+
+ return decoded_chars
+
+
+print(f"serial {args.com_port}:{args.baudrate}\nTCP server started on {args.ip_address}:{args.port}, Waiting for client connection...")
+
+while True:
+
+
+ # Accept a client connection
+ conn, addr = tcp_server_socket.accept()
+ print("Client connected. IP address:", addr)
+
+ # Create a serial connection
+ serial_port = serial.Serial(args.com_port, baudrate=args.baudrate, timeout=0.001)
+
+ #handle file dump
+ tx = None
+ if args.tx:
+ tx = open(args.tx,"ab");
+ rx = None
+ if args.rx:
+ rx = open(args.rx,"ab");
+
+ def read_serial_and_send():
+ while True:
+ try:
+ # Read data from the serial port
+ serial_data = serial_port.read(BUFFER_SIZE)
+ if serial_data:
+ # Send data back to the client
+ conn.send(serial_data)
+ if verbos:
+ print(f"port({len(serial_data)}):", custom_decode(serial_data))
+ if tx:
+ tx.write(serial_data)
+ tx.flush();
+ except:
+ conn.close()
+ break
+
+ def receive_client_data():
+ while True:
+ try:
+ # Receive data from the client
+ data = conn.recv(BUFFER_SIZE)
+ if not data:
+ raise
+ except:
+ print("Client disconnected: ",addr)
+ break
+
+ # Print received data
+ if verbos:
+ print(f"client({len(data)}):", custom_decode(data))
+ if rx:
+ rx.write(data)
+ rx.flush();
+ try:
+ # Send data to the serial port
+ serial_port.write(data)
+ except:
+ print("cannt write data to serial");
+ break
+
+ # Start the threads
+ read_thread = threading.Thread(target=read_serial_and_send)
+ read_thread.start()
+
+ receive_thread = threading.Thread(target=receive_client_data)
+ receive_thread.start()
+
+
+ # Wait for the threads to finish
+ # read_thread.join()
+ receive_thread.join()
+
+ # Close the TCP connection and serial port
+ print("close client and serial")
+ conn.close()
+ serial_port.close()
+ if tx:
+ tx.close()
+ if rx:
+ rx.close()
+
+# Close the TCP server socket
+tcp_server_socket.close()
diff --git a/Examples/StreamOverSocket/uart_sock.c b/Examples/StreamOverSocket/uart_sock.c
new file mode 100644
index 0000000..02ea8ab
--- /dev/null
+++ b/Examples/StreamOverSocket/uart_sock.c
@@ -0,0 +1,184 @@
+#include
+#include "stdbool.h"
+#include "stdint.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include
+
+// bool dumpData = false;
+typedef struct {
+ SOCKET sock;
+ struct sockaddr_in server;
+ volatile bool isRunnig;
+ const char *name;
+
+ pthread_t sendThread;
+ void *txBuffer;
+ pthread_cond_t txCond;
+ pthread_mutex_t txMutex;
+ size_t inTx;
+ void (*txComp)(void *);
+
+
+ pthread_t recThread;
+ uint8_t *rxBuffer;
+ pthread_cond_t rxCond;
+ pthread_mutex_t rxMutex;
+ size_t inRx;
+ void (*rxComp)(void *);
+
+
+
+ void *args;
+} UARTStreamOverSocket;
+
+void *SendThread(void *args) {
+ UARTStreamOverSocket *stream = (UARTStreamOverSocket *) args;
+ SOCKET s = stream->sock;
+ while (1) {
+ pthread_mutex_lock(&stream->txMutex);
+ while (stream->inTx == 0) {
+ pthread_cond_wait(&stream->txCond, &stream->txMutex);
+ }
+ while (stream->inTx != 0) {
+ int sent = send(s, stream->txBuffer, stream->inTx, 0);
+ if (send < 0) {
+ printf("%s->Send Failed.Error Code: %d .Exiting...\n", stream->name, sent);
+ exit(0);
+ }
+ stream->inTx -= sent;
+ stream->txBuffer += sent;
+ }
+ pthread_mutex_unlock(&stream->txMutex);
+
+ if (stream->txComp != NULL) {
+ stream->txComp(stream->args);
+ }
+ }
+}
+
+// Function executed by the receiving thread
+void *ReceiveThread(void *args) {
+ UARTStreamOverSocket *stream = (UARTStreamOverSocket *) args;
+ SOCKET socket = stream->sock;
+ int recv_size;
+
+ while (1) {
+ pthread_mutex_lock(&stream->rxMutex);
+ while (stream->inRx == 0) {
+ pthread_cond_wait(&stream->rxCond, &stream->rxMutex);
+ }
+ while(stream->inRx != 0) {
+ recv_size = recv(socket, (char *) stream->rxBuffer, stream->inRx, 0);
+ if (recv_size > 0) {
+ stream->inRx -= recv_size;
+ stream->rxBuffer += recv_size;
+ }
+ else {
+ printf("%s->disconnected.Exiting...\n", stream->name);
+ exit(0);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&stream->rxMutex);
+
+ if (stream->rxComp != NULL) {
+ stream->rxComp(stream->args);
+ }
+
+ }
+}
+
+size_t socketinReceive(void *obj)
+{
+ UARTStreamOverSocket *stream = (UARTStreamOverSocket *)obj;
+ return stream->inRx;
+}
+
+void socketReceive(void *obj, uint8_t *buffer, size_t len) {
+ UARTStreamOverSocket *stream = (UARTStreamOverSocket *) obj;
+ pthread_mutex_lock(&stream->rxMutex);
+
+ // Set the data and signal the sending thread
+
+ stream->rxBuffer = buffer;
+ stream->inRx = len;
+
+ pthread_cond_signal(&stream->rxCond);
+ pthread_mutex_unlock(&stream->rxMutex);
+}
+
+void socketTransmit(void *obj, uint8_t *buffer, size_t len) {
+ UARTStreamOverSocket *stream = (UARTStreamOverSocket *) obj;
+ pthread_mutex_lock(&stream->txMutex);
+
+ // Set the data and signal the sending thread
+
+ stream->txBuffer = buffer;
+ stream->inTx = len;
+
+ pthread_cond_signal(&stream->txCond);
+ pthread_mutex_unlock(&stream->txMutex);
+
+}
+
+void *socketInit(void *args, const char *ip, uint16_t port, const char *name, void (*txComp)(void *),
+ void (*rxComp)(void *)) {
+ UARTStreamOverSocket *stream = malloc(sizeof(UARTStreamOverSocket));
+ if (stream == NULL) {
+ printf("%s->cannot alloc memory\n", name);
+ return NULL;
+ }
+ // stream->HUART = huart;
+ stream->name = name;
+ stream->isRunnig = false;
+ stream->txComp = txComp;
+ stream->rxComp = rxComp;
+ stream->args = args;
+ stream->inTx = stream->inRx = 0;
+ // Create a socket
+ if ((stream->sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
+ printf("%s->Could not create socket : %d\n", stream->name, WSAGetLastError());
+ return NULL;
+ }
+// printf("%s->Socket created.\n", stream->name);
+
+ stream->server.sin_addr.s_addr = inet_addr(ip); // Replace with the IP address of your server
+ stream->server.sin_family = AF_INET;
+ stream->server.sin_port = htons(port); // Replace with the port number of your server
+
+ // Connect to remote server
+ if (connect(stream->sock, (struct sockaddr *) &stream->server, sizeof(stream->server)) < 0) {
+ printf("%s->Connect error\n", stream->name);
+ return NULL;
+ }
+
+ printf("%s->Connected\n", stream->name);
+
+ stream->rxCond = PTHREAD_COND_INITIALIZER;
+ stream->rxMutex = PTHREAD_MUTEX_INITIALIZER;
+ int ret = pthread_create(&stream->recThread, NULL, ReceiveThread, stream);
+ if (ret != 0) {
+ printf("%s->Failed to create ReceiveThread.Error Code: %d\n", stream->name, ret);
+ return NULL;
+ }
+
+ stream->txCond = PTHREAD_COND_INITIALIZER;
+ stream->txMutex = PTHREAD_MUTEX_INITIALIZER;
+ ret = pthread_create(&stream->sendThread, NULL, SendThread, stream);
+ if (ret != 0) {
+ printf("%s->Failed to create SendThread.Error Code: %d\n", stream->name, ret);
+ pthread_cancel(stream->recThread);
+ // Wait for the created thread to finish (note that it may not terminate immediately)
+ pthread_join(stream->recThread, NULL);
+ return NULL;
+ }
+ Sleep(1);
+ stream->isRunnig = true;
+ return stream;
+}
+
+void socketDeInit(void *obj) {
+ closesocket(((UARTStreamOverSocket *) obj)->sock);
+ free(obj);
+}
diff --git a/Examples/StreamOverSocket/userCodes.c b/Examples/StreamOverSocket/userCodes.c
new file mode 100644
index 0000000..dfa989e
--- /dev/null
+++ b/Examples/StreamOverSocket/userCodes.c
@@ -0,0 +1,40 @@
+#include
+#include
+#include "string.h"
+#include "UARTStream.h"
+#include "Str.h"
+#include "arduino.h"
+
+
+uint8_t rxBuf1[64];
+uint8_t txBuf1[64];
+UARTStream uart1;
+
+
+void setup()
+{
+ millis(); // reference it from now
+ setbuf(stdout, NULL); // Disable buffering for stdout
+ bool ret = UARTStream_init(
+ &uart1, "127.0.0.1", 8888, "COM16",
+ rxBuf1, sizeof(rxBuf1),
+ txBuf1, sizeof(txBuf1));
+ if (ret == false)
+ {
+ printf("ret == false");
+ exit(0);
+ }
+
+
+ IStream_receive(&uart1.Input);
+
+}
+void loop()
+{
+ if(IStream_available(&uart1.Input)) {
+ OStream_writeStream(&uart1.Output, &uart1.Input, IStream_available(&uart1.Input));
+ OStream_flush(&uart1.Output);
+ }
+
+}
+